package main

import (
	"database/sql"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	_ "github.com/denisenkom/go-mssqldb"
	"github.com/gorilla/sessions"
)

var store *sessions.CookieStore

func init() {
	store = sessions.NewCookieStore([]byte("ehongmd-secret-key-2025"))
	// Configure store options for better compatibility with non-HTTPS IP access
	store.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   3600 * 24, // 1 day
		HttpOnly: true,
		Secure:   false, // Set to true only if using HTTPS
		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
}

type Branch struct {
	ID   string
	Name string
}

type Zone struct {
	Code string
	Nick string
}

type Region struct {
	StaffID   string
	StaffName string
}

type Brand struct {
	ID   string
	Name 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

		// Diagnostic: Ensure session is saved correctly
		if err := session.Save(r, w); err != nil {
			log.Printf("[SESSION ERROR] Failed to save session for %s: %v", user, err)
			http.Error(w, "Failed to initialize session", http.StatusInternalServerError)
			return
		}

		log.Printf("[SESSION DEBUG] Successfully saved session for %s. Redirecting to /ehongmd/main", user)
		// 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("/", 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("[SESSION ERROR] Unauthorized attempt to access %s. No valid user_id in session. Redirecting to login.", 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"
		}

		// 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)

				if htmlFile == "ehongmd/ecc_report.html" {
					// Fetch Branches
					var branches []Branch
					rows, err := db.Query("SELECT BR_ID, BR_NAME FROM EHONGDB.dbo.BRANCH WHERE BR_NAME NOT IN ('รวมทุกสาขา') ORDER BY BR_ID")
					if err == nil {
						for rows.Next() {
							var b Branch
							if err := rows.Scan(&b.ID, &b.Name); err == nil {
								branches = append(branches, b)
							}
						}
						rows.Close()
					}
					templateData["Branches"] = branches

					// Fetch Zones
					var zones []Zone
					rows, err = db.Query("SELECT szone_code, staff_nick FROM EHONGDB.dbo.branch_salezone ORDER BY szone_code")
					if err == nil {
						for rows.Next() {
							var z Zone
							var nick sql.NullString
							if err := rows.Scan(&z.Code, &nick); err == nil {
								if nick.Valid {
									z.Nick = nick.String
								}
								zones = append(zones, z)
							}
						}
						rows.Close()
					}
					templateData["Zones"] = zones

					// Fetch Regions
					var regions []Region
					rows, err = db.Query("SELECT DISTINCT zstaff_id, zstaff_name FROM EHONGDB.dbo.branch_salezone ORDER BY zstaff_id")
					if err == nil {
						for rows.Next() {
							var r Region
							var id, name sql.NullString
							if err := rows.Scan(&id, &name); err == nil {
								if id.Valid {
									r.StaffID = id.String
								}
								if name.Valid {
									r.StaffName = name.String
								}
								regions = append(regions, r)
							}
						}
						rows.Close()
					}
					templateData["Regions"] = regions

					// Fetch Brands
					var brands []Brand
					rows, err = db.Query("SELECT BRAND_ID, BRAND_NAME FROM CONFIG.dbo.NEWEHONGMD_BRAND WHERE BRAND_ID NOT IN ('8','10','11','20') ORDER BY BRAND_ID")
					if err == nil {
						for rows.Next() {
							var b Brand
							if err := rows.Scan(&b.ID, &b.Name); err == nil {
								brands = append(brands, b)
							}
						}
						rows.Close()
					}
					templateData["Brands"] = brands

					if r.Method == http.MethodPost {
						r.ParseMultipartForm(10 << 20)
						templateData["FormDMY1"] = r.FormValue("DMY1")
						templateData["FormDMY2"] = r.FormValue("DMY2")
						templateData["FormBR_ID"] = r.FormValue("BR_ID")
						templateData["FormSzoneCode"] = r.FormValue("szone_code")
						templateData["FormZstaffID"] = r.FormValue("zstaff_id")
						templateData["FormBrandID"] = r.FormValue("BRAND_ID")
					} else {
						// Default dates
						firstDay := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
						templateData["FormDMY1"] = firstDay.Format("2006-01-02")
						templateData["FormDMY2"] = now.Format("2006-01-02")
					}

					formDMY1, _ := templateData["FormDMY1"].(string)
					formDMY2, _ := templateData["FormDMY2"].(string)
					formBR_ID, _ := templateData["FormBR_ID"].(string)
					formSzoneCode, _ := templateData["FormSzoneCode"].(string)
					formZstaffID, _ := templateData["FormZstaffID"].(string)

					reportRows, summary := GetEccReportData(db, formDMY1, formDMY2, formBR_ID, formSzoneCode, formZstaffID)
					templateData["ReportRows"] = reportRows
					templateData["ReportSummary"] = summary
				}

				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",
				}

				tmpl := template.New(filepath.Base(htmlFile)).Funcs(template.FuncMap{
					"formatNum": func(f float64, dec int) string {
						if f <= 0 {
							return ""
						}
						s := fmt.Sprintf(fmt.Sprintf("%%.%df", dec), f)
						parts := strings.Split(s, ".")
						intPart := parts[0]
						n := len(intPart)
						var buf []byte
						for i := 0; i < n; i++ {
							buf = append(buf, intPart[i])
							if (n-i-1)%3 == 0 && i != n-1 {
								buf = append(buf, ',')
							}
						}
						if len(parts) > 1 {
							return string(buf) + "." + parts[1]
						}
						return string(buf)
					},
					"formatNumZero": func(f float64, dec int) string {
						s := fmt.Sprintf(fmt.Sprintf("%%.%df", dec), f)
						parts := strings.Split(s, ".")
						intPart := parts[0]
						n := len(intPart)
						var buf []byte
						for i := 0; i < n; i++ {
							buf = append(buf, intPart[i])
							if (n-i-1)%3 == 0 && i != n-1 {
								buf = append(buf, ',')
							}
						}
						if len(parts) > 1 {
							return string(buf) + "." + parts[1]
						}
						return string(buf)
					},
				})
				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:9902")
	log.Fatal(http.ListenAndServe(":9902", nil))
}
