package main

import (
	"database/sql"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"my-web-server/ehongmd/ehongmd/main_1"

	_ "github.com/denisenkom/go-mssqldb"
	"github.com/gorilla/sessions"
)

var store = sessions.NewCookieStore([]byte("ehongmd-secret-key-2025"))

func init() {
	store.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   86400 * 7,
		HttpOnly: true,
		Secure:   false, // Since we are using HTTP (not HTTPS) on local IP
		SameSite: http.SameSiteLaxMode,
	}
}

type Employee struct {
	EMP_ID    string
	US_NAME   string
	BARCODE   string
	US_PASSWD string
	TNAME     string
	FNAME     string
	LNAME     string
	NICK      string
}

func main() {
	// 1. กำหนดค่าการเชื่อมต่อ (Connection String)
	connStr := "server=192.168.10.61;user id=pond;password=Ehongmd2025;port=1433;database=CONFIG;encrypt=disable"

	// 2. เปิดการเชื่อมต่อ Database
	db, err := sql.Open("sqlserver", connStr)
	if err != nil {
		log.Fatal("Error opening database: ", err)
	}
	defer db.Close()

	// 3. ตรวจสอบว่าเชื่อมต่อได้จริงหรือไม่ (Ping)
	err = db.Ping()
	if err != nil {
		log.Fatal("Cannot connect to database: ", err)
	}
	fmt.Println("Successfully connected to SQL Server!")

	// 4. จัดการ Routing สำหรับ Web Server
	// Serve static files with logging
	staticHandler := func(prefix, dir string) http.Handler {
		return http.StripPrefix(prefix, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			log.Printf("Static request: %s -> %s%s", r.URL.Path, dir, r.URL.Path)
			http.FileServer(http.Dir(dir)).ServeHTTP(w, r)
		}))
	}

	http.Handle("/assets/", staticHandler("/assets/", "ehongmd/assets/"))
	http.Handle("/images/", staticHandler("/images/", "ehongmd/images/"))
	http.Handle("/css/", staticHandler("/css/", "ehongmd/css/"))
	http.Handle("/js/", staticHandler("/js/", "ehongmd/js/"))

	// Login Handler
	http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			http.Redirect(w, r, "/ehongmd/index.html", http.StatusSeeOther)
			return
		}

		user := r.FormValue("USER")
		pass := r.FormValue("PASS")

		log.Printf("Login attempt for user: %s", user)

		var emp Employee
		err := db.QueryRow(`
			SELECT EMP_ID, US_NAME, BARCODE, US_PASSWD, TNAME, FNAME, LNAME, NICK 
			FROM EHONGDB.dbo.EMPLOYEE 
			WHERE EM_STATUS = 'NM' 
			AND (US_NAME = @p1 OR BARCODE = @p2) 
			AND US_PASSWD = @p3
		`, user, user, pass).Scan(&emp.EMP_ID, &emp.US_NAME, &emp.BARCODE, &emp.US_PASSWD, &emp.TNAME, &emp.FNAME, &emp.LNAME, &emp.NICK)

		if err != nil {
			if err == sql.ErrNoRows {
				log.Printf("Login failed for user: %s (Invalid credentials)", user)
				http.Redirect(w, r, "/ehongmd/index.html?error=invalid", http.StatusSeeOther)
			} else {
				log.Printf("Database error during login: %v", err)
				http.Error(w, "Database error", http.StatusInternalServerError)
			}
			return
		}

		log.Printf("Login successful for: %s (%s %s)", emp.US_NAME, emp.FNAME, emp.LNAME)

		// Create session
		session, _ := store.Get(r, "ehong-session")
		session.Values["user_id"] = emp.EMP_ID
		session.Values["user_name"] = emp.US_NAME
		session.Values["full_name"] = emp.FNAME + " " + emp.LNAME
		session.Save(r, w)

		// Redirect to main
		http.Redirect(w, r, "/ehongmd/main", http.StatusSeeOther)
	})

	// Logout Handler
	http.HandleFunc("/logout", func(w http.ResponseWriter, r *http.Request) {
		session, _ := store.Get(r, "ehong-session")
		session.Options.MaxAge = -1
		session.Save(r, w)
		http.Redirect(w, r, "/ehongmd/index.html", http.StatusSeeOther)
	})

	http.HandleFunc("/ehongmd/main_1/upload_csv", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			return
		}

		file, header, err := r.FormFile("csv_file")
		if err != nil {
			http.Error(w, "Error retrieving the file", http.StatusBadRequest)
			return
		}
		defer file.Close()

		// ดึงข้อมูลผู้ใช้งานจาก Session
		session, _ := store.Get(r, "ehong-session")
		userName, _ := session.Values["user_name"].(string)
		fileName := header.Filename

		reader := csv.NewReader(file)
		records, err := reader.ReadAll()
		if err != nil {
			http.Error(w, "Error reading CSV", http.StatusInternalServerError)
			return
		}

		err = main_1.SaveLoanCSV(db, records, userName, fileName)
		if err != nil {
			http.Error(w, "Error saving to database: "+err.Error(), http.StatusInternalServerError)
			return
		}

		fmt.Fprint(w, "Success")
	})

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path

		// Check session for backend pages
		if strings.HasPrefix(path, "/ehongmd/") &&
			!strings.HasSuffix(path, "index.html") &&
			!strings.Contains(path, "/css/") &&
			!strings.Contains(path, "/js/") &&
			!strings.Contains(path, "/images/") {

			session, _ := store.Get(r, "ehong-session")
			if auth, ok := session.Values["user_id"].(string); !ok || auth == "" {
				log.Printf("Unauthorized access attempt to: %s", path)
				http.Redirect(w, r, "/ehongmd/index.html", http.StatusSeeOther)
				return
			}
		}

		if path == "/" {
			http.ServeFile(w, r, "ehongmd/index.html")
			return
		}

		// Remove leading slash for local file path
		cleanPath := strings.TrimPrefix(path, "/")

		// Determine the base name without extension for matching
		basePath := strings.TrimSuffix(cleanPath, ".html")
		basePath = strings.TrimSuffix(basePath, "/") // Trim trailing slash
		if basePath == "" {
			basePath = "index"
		}

		// API: Fetch Loan 3 Group Details (JSON) - Move BEFORE template logic
		if strings.HasSuffix(basePath, "api/loan3/group_details") {
			year := r.URL.Query().Get("year")
			month := r.URL.Query().Get("month")
			lType := r.URL.Query().Get("type")
			usName := r.URL.Query().Get("usName")
			if usName == "" {
				usName = "UNASSIGNED"
			}
			
			allData := main_1.FetchLoan3Report(db, year, month, usName)
			var filtered []main_1.Loan3Record
			for _, rec := range allData {
				trimmedType := strings.TrimSpace(rec.L_TYPE)
				if lType == "TOTAL" || trimmedType == lType {
					filtered = append(filtered, rec)
				}
			}
			
			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(filtered)
			return
		}

		// API: Fetch Loan 3 Transaction Details (hps_tran) (JSON)
		if strings.HasSuffix(basePath, "api/loan3/tran_details") {
			year := r.URL.Query().Get("year")
			month := r.URL.Query().Get("month")
			lType := r.URL.Query().Get("type")
			usName := r.URL.Query().Get("usName")

			details := main_1.FetchLoan3TranDetails(db, year, month, lType, usName)
			if details == nil {
				details = []main_1.TranDetail{}
			}
			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(details)
			return
		}

		// API: Assign Loan 3 Employee (JSON POST)
		if strings.HasSuffix(basePath, "api/loan3/assign_employee") && r.Method == "POST" {
			var req struct {
				Year   string   `json:"year"`
				Month  string   `json:"month"`
				UsName string   `json:"usName"`
				CtNos  []string `json:"ctNos"`
			}
			if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
				http.Error(w, "Invalid request body", http.StatusBadRequest)
				return
			}
			err := main_1.UpdateLoan3Employee(db, req.Year, req.Month, req.UsName, req.CtNos)
			if err != nil {
				http.Error(w, "Error saving data", http.StatusInternalServerError)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(map[string]string{"status": "success"})
			return
		}

		// If path has no extension or is .html, try processing as template
		ext := filepath.Ext(cleanPath)
		if ext == "" || ext == ".html" || strings.HasSuffix(cleanPath, "/") {
			htmlFile := basePath + ".html"
			if _, err := os.Stat(htmlFile); err == nil {
				// Prepare template data
				type UserInfo struct {
					UserID   string
					UserName string
					FullName string
				}

				session, _ := store.Get(r, "ehong-session")
				var user UserInfo
				if uid, ok := session.Values["user_id"].(string); ok {
					user.UserID = uid
					user.UserName = session.Values["user_name"].(string)
					user.FullName = session.Values["full_name"].(string)
				}

				templateData := make(map[string]interface{})
				// Prepare Thai Date
				thaiMonths := []string{
					"มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน",
					"กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม",
				}
				now := time.Now()
				thaiYear := now.Year() + 543
				thaiMonth := thaiMonths[now.Month()-1]
				templateData["CurrentDate"] = fmt.Sprintf("%d %s %d", now.Day(), thaiMonth, thaiYear)

				templateData["User"] = user
				templateData["CurrentYear"] = now.Year()
				templateData["CurrentPage"] = filepath.Base(basePath)
				templateData["FullPage"] = basePath

				if strings.Contains(basePath, "main_1") {
					templateData["MenuArea"] = "main_1"
				} else if strings.Contains(basePath, "main_2") {
					templateData["MenuArea"] = "main_2"
				} else if strings.Contains(basePath, "main_3") {
					templateData["MenuArea"] = "main_3"
				}

				// Fetch Employee Data for main_1/index (Called from package main_1)
				if basePath == "ehongmd/ehongmd/main_1/index" {
					year := r.URL.Query().Get("year")
					month := r.URL.Query().Get("month")
					
					// ถ้าไม่ได้ระบุ ให้หาล่าสุดเพื่อเอามาแสดงในหน้าเว็บ
					periods := main_1.FetchLoan3AvailablePeriods(db)
					if year == "" && month == "" && len(periods) > 0 {
						year = periods[0].Year
						month = periods[0].Month
					}
					
					templateData["Employees"] = main_1.FetchLoanEmployees(db, year, month)
					templateData["OverallSummary"] = main_1.FetchLoan3OverallSummary(db, year, month)
					templateData["AvailablePeriods"] = periods
					templateData["SelectedYear"] = year
					templateData["SelectedMonth"] = month
				}

				// Fetch Loan 3 Report Data
				if basePath == "ehongmd/ehongmd/main_1/index_loan3_report" {
					availablePeriods := main_1.FetchLoan3AvailablePeriods(db)
					templateData["AvailablePeriods"] = availablePeriods

					year := r.URL.Query().Get("year")
					month := r.URL.Query().Get("month")

					// ถ้าไม่ได้ระบุ ให้ใช้เดือนล่าสุดที่มีข้อมูล
					if (year == "" || month == "") && len(availablePeriods) > 0 {
						year = availablePeriods[0].Year
						month = availablePeriods[0].Month
					}

					templateData["SelectedYear"] = year
					templateData["SelectedMonth"] = month
					templateData["Employees"] = main_1.FetchLoanEmployees(db, year, month)
					templateData["OverallSummary"] = main_1.FetchLoan3OverallSummary(db, year, month)
				}

				// Use Go Template to include navbar, footer, etc.
				tmplFiles := []string{
					htmlFile,
					// "templates/navbar.html",
					// "templates/footer.html",
					// "templates/head_links.html",
					"ehongmd/templates/backend_head.html",
					"ehongmd/templates/backend_header.html",
					"ehongmd/templates/backend_menu.html",
					"ehongmd/templates/backend_footer.html",
					"ehongmd/templates/backend_js.html",
				}
				// Use Go Template with FuncMap
				funcMap := template.FuncMap{
					"add": func(a, b int) int {
						return a + b
					},
					"percent": func(a, b interface{}) string {
						var valA, valB float64
						switch v := a.(type) {
						case int: valA = float64(v)
						case int64: valA = float64(v)
						case float64: valA = v
						}
						switch v := b.(type) {
						case int: valB = float64(v)
						case int64: valB = float64(v)
						case float64: valB = v
						}
						if valB <= 0 {
							return "0.00"
						}
						return fmt.Sprintf("%.2f", (valA/valB)*100)
					},
				}

				tmpl := template.New(filepath.Base(htmlFile)).Funcs(funcMap)
				tmpl, err = tmpl.ParseFiles(tmplFiles...)
				if err != nil {
					log.Println("Error parsing templates:", err)
					http.Error(w, err.Error(), http.StatusInternalServerError)
					return
				}
				err = tmpl.Execute(w, templateData)
				if err != nil {
					log.Println("Error executing template:", err)
				}
				return
			}
		}

		// Fallback to ServeFile for assets or specific extensions
		fPath := "." + r.URL.Path
		if _, err := os.Stat(fPath); os.IsNotExist(err) {
			fPath = "ehongmd" + r.URL.Path
		}
		log.Printf("Serving file: %s -> %s", r.URL.Path, fPath)
		http.ServeFile(w, r, fPath)
	})

	// 5. กำหนด Port และรัน Server
	fmt.Println("✅ Server running at http://localhost:9111")
	log.Fatal(http.ListenAndServe(":9111", nil))
}
