package main

import (
	"fmt"
	"log"
	"time"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"github.com/golang-jwt/jwt/v5"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

// 👤 1. โครงสร้างตารางข้อมูลพนักงาน
type User struct {
	gorm.Model
	Username   string `gorm:"unique;not null" json:"username"`
	Password   string `gorm:"not null" json:"-"`
	FullName   string `json:"full_name"`
	Department string `json:"department"` // ฝ่ายพัฒนาเกม, ไอที, บัญชี, บริหารงานบุคคล
	Position   string `json:"position"`
	Role       string `gorm:"default:employee" json:"role"` // admin, head, employee
}

// 📋 2. โครงสร้างตารางจัดสรรงานรายสัปดาห์
type WeeklyTask struct {
	gorm.Model
	EmployeeID    uint   `json:"employee_id"`
	EmployeeName  string `json:"employee_name"`
	Department    string `json:"department"`
	WeekRange     string `json:"week_range"`
	TaskStartDate string `json:"task_start_date"` // รูปแบบ YYYY-MM-DD ใช้คำนวณแถบ Gantt
	TaskEndDate   string `json:"task_end_date"`   // รูปแบบ YYYY-MM-DD ใช้คำนวณแถบ Gantt
	TaskDetails   string `json:"task_details"`
	CreatedBy     string `json:"created_by"`
	TaskStatus    string `json:"task_status"` // "assigned", "in_progress", "done"
}

// 🏢 3. โครงสร้างตารางสังกัดแผนก
type Department struct {
	gorm.Model
	Name string `gorm:"unique;not null" json:"name"`
}

// 📋 4. บันทึกประวัติการแก้ไขข้อมูลพนักงานโดย Admin
type UserEditLog struct {
	gorm.Model
	TargetUserID   uint   `json:"target_user_id"`
	TargetUsername string `json:"target_username"`
	TargetFullName string `json:"target_full_name"`
	AdminName      string `json:"admin_name"`    // ชื่อ admin ที่แก้ไข
	FieldChanged   string `json:"field_changed"` // เช่น "full_name, department"
	OldValue       string `json:"old_value"`     // ค่าเดิม (JSON string)
	NewValue       string `json:"new_value"`     // ค่าใหม่ (JSON string)
	EditedAt       string `json:"edited_at"`     // เวลาที่แก้ไข (ISO string)
}

// 📝 5. โครงสร้างตารางบันทึกความคืบหน้างานรายวัน
type DailyLog struct {
	gorm.Model
	EmployeeID   uint   `json:"employee_id"`
	EmployeeName string `json:"employee_name"`
	LogDate      string `json:"log_date"` // รูปแบบ YYYY-MM-DD
	Note         string `json:"note"`
	CreatedBy    string `json:"created_by"`
}

// 🚜 6. โครงสร้างตารางเครื่องจักร (สินทรัพย์ของบริษัท)
type Machine struct {
	gorm.Model
	Name   string `gorm:"not null" json:"name"`            // ชื่อ/รุ่นเครื่องจักร เช่น "รถขุด PC200"
	Code   string `gorm:"unique;not null" json:"code"`     // เลขทะเบียน/รหัสเครื่อง
	Type   string `json:"type"`                            // ประเภทเครื่องจักร
	Status string `gorm:"default:available" json:"status"` // available, in_use, maintenance
}

// 🧾 7. โครงสร้างตารางบันทึกการเบิก-คืนเครื่องจักร
type MachineCheckout struct {
	gorm.Model
	MachineID    uint   `json:"machine_id"`
	MachineName  string `json:"machine_name"`
	JobName      string `json:"job_name"`      // เอาออกไปใช้งานไหน
	Location     string `json:"location"`      // เอาออกไปใช้ที่ไหน
	CheckoutDate string `json:"checkout_date"` // วันที่เอาออกไปใช้ YYYY-MM-DD
	DueDate      string `json:"due_date"`      // กำหนดคืนวันไหน YYYY-MM-DD
	ReturnedDate string `json:"returned_date"` // วันที่คืนจริง (ว่างถ้ายังไม่คืน)
	Status       string `json:"status"`        // out, returned
	Note         string `json:"note"`
	CreatedBy    string `json:"created_by"` // ชื่อผู้บันทึก (เจ้าหน้าที่เครื่องจักร)
}

var DB *gorm.DB
var jwtSecret = []byte("tycoon_lan_secure_key_2026")

func initDatabase() {
	myPassword := "1234" // ⚠️ รหัสผ่าน PostgreSQL ของเครื่องคุณ

	rootDsn := fmt.Sprintf("host=localhost user=postgres password=%s dbname=postgres port=5432 sslmode=disable TimeZone=Asia/Bangkok", myPassword)
	rootDB, err := gorm.Open(postgres.Open(rootDsn), &gorm.Config{})
	if err != nil {
		log.Fatal("❌ เชื่อมต่อฐานข้อมูลหลักล้มเหลว: ", err)
	}

	var exists int
	rootDB.Raw("SELECT 1 FROM pg_database WHERE datname = 'tycoon_tasks'").Scan(&exists)
	if exists != 1 {
		err = rootDB.Exec("CREATE DATABASE tycoon_tasks").Error
		if err != nil {
			log.Fatal("❌ สร้างฐานข้อมูล tycoon_tasks ไม่สำเร็จ: ", err)
		}
		fmt.Println("✨ ระบบทำการสร้างก้อนฐานข้อมูลระบบงาน tycoon_tasks ให้ใหม่เรียบร้อย!")
	}

	dsn := fmt.Sprintf("host=localhost user=postgres password=%s dbname=tycoon_tasks port=5432 sslmode=disable TimeZone=Asia/Bangkok", myPassword)
	DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal("❌ เชื่อมต่อฐานข้อมูลระบบงานล้มเหลว: ", err)
	}
	fmt.Println("📦 เชื่อมต่อฐานข้อมูล PostgreSQL (tycoon_tasks) สำเร็จ!")

	DB.AutoMigrate(&User{}, &WeeklyTask{}, &Department{}, &DailyLog{}, &UserEditLog{}, &Machine{}, &MachineCheckout{})
	seedInitialUsers()
	seedInitialDepartments()
}

func seedInitialDepartments() {
	defaultDepts := []string{"ฝ่ายพัฒนาเกม", "ฝ่ายไอทีและซัพพอร์ต", "ฝ่ายการตลาด", "ฝ่ายบริหารงานบุคคล"}
	for _, name := range defaultDepts {
		var count int64
		DB.Model(&Department{}).Where("name = ?", name).Count(&count)
		if count == 0 {
			DB.Create(&Department{Name: name})
		}
	}
}

func seedInitialUsers() {
	hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost)

	// 👑 1. ตรวจสอบและบังคับสร้างบัญชี Admin
	var adminCount int64
	DB.Model(&User{}).Where("username = ?", "admin01").Count(&adminCount)
	if adminCount == 0 {
		adminUser := User{
			Username:   "admin01",
			Password:   string(hashedPassword),
			FullName:   "ผู้ดูแลระบบ ไทคูณ",
			Department: "ฝ่ายบริหารงานบุคคล",
			Position:   "HR Admin",
			Role:       "admin",
		}
		DB.Create(&adminUser)
		fmt.Println("✨ [ระบบ] ได้ทำการเพิ่มบัญชีเด็ดขาด admin01 เข้าฐานข้อมูลเรียบร้อยแล้ว!")
	}

	// 2. ตรวจสอบและสร้างบัญชี Head
	var headCount int64
	DB.Model(&User{}).Where("username = ?", "boss01").Count(&headCount)
	if headCount == 0 {
		headUser := User{
			Username:   "boss01",
			Password:   string(hashedPassword),
			FullName:   "หัวหน้าสมศักดิ์ รักทีม",
			Department: "ฝ่ายพัฒนาเกม",
			Position:   "Game Dev Team Lead",
			Role:       "head",
		}
		DB.Create(&headUser)
	}

	// 3. ตรวจสอบและสร้างบัญชี Employee
	var empCount int64
	DB.Model(&User{}).Where("username = ?", "pond01").Count(&empCount)
	if empCount == 0 {
		empUser := User{
			Username:   "pond01",
			Password:   string(hashedPassword),
			FullName:   "พนักงานพงศธร ลุยงาน",
			Department: "ฝ่ายพัฒนาเกม",
			Position:   "2D Game Developer",
			Role:       "employee",
		}
		DB.Create(&empUser)
	}
	// 4. ตรวจสอบและสร้างบัญชีเจ้าหน้าที่เครื่องจักร
	var machineOfficerCount int64
	DB.Model(&User{}).Where("username = ?", "mech01").Count(&machineOfficerCount)
	if machineOfficerCount == 0 {
		mechUser := User{
			Username:   "mech01",
			Password:   string(hashedPassword),
			FullName:   "เจ้าหน้าที่เอกชัย ดูแลเครื่อง",
			Department: "ฝ่ายเครื่องจักรและอุปกรณ์",
			Position:   "Machine Controller",
			Role:       "machine",
		}
		DB.Create(&mechUser)
	}
}

func LoginHandler(c *fiber.Ctx) error {
	type LoginInput struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}
	var input LoginInput
	if err := c.BodyParser(&input); err != nil {
		return c.Status(400).JSON(fiber.Map{"message": "รูปแบบข้อมูลไม่ถูกต้อง"})
	}

	var user User
	if err := DB.Where("username = ?", input.Username).First(&user).Error; err != nil {
		return c.Status(401).JSON(fiber.Map{"message": "ไม่พบชื่อผู้ใช้งานในระบบ"})
	}

	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(input.Password)); err != nil {
		return c.Status(401).JSON(fiber.Map{"message": "รหัสผ่านไม่ถูกต้อง"})
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"user_id": user.ID,
		"role":    user.Role,
		"exp":     time.Now().Add(time.Hour * 24).Unix(),
	})
	tokenString, _ := token.SignedString(jwtSecret)

	return c.JSON(fiber.Map{"token": tokenString, "user": user})
}

func main() {
	initDatabase()

	app := fiber.New()

	app.Use(cors.New())

	app.Get("/", func(c *fiber.Ctx) error {
		return c.SendString("ระบบหลังบ้านจัดสรรคนและภาระงานรายสัปดาห์ (LAN Server) พร้อมทำงาน! 🚀")
	})

	app.Post("/api/login", LoginHandler)

	// 🔥 --- [ADMIN FEATURE] API สำหรับให้ Admin เพิ่มพนักงานใหม่เข้าระบบ ---
	app.Post("/api/users", func(c *fiber.Ctx) error {
		type CreateUserInput struct {
			Username   string `json:"username"`
			Password   string `json:"password"`
			FullName   string `json:"full_name"`
			Department string `json:"department"`
			Position   string `json:"position"`
			Role       string `json:"role"`
		}

		var input CreateUserInput
		if err := c.BodyParser(&input); err != nil {
			return c.Status(400).JSON(fiber.Map{"message": "ข้อมูลพนักงานไม่ถูกต้อง"})
		}

		// เช็กว่า Username ซ้ำไหม
		var existUser User
		if err := DB.Where("username = ?", input.Username).First(&existUser).Error; err == nil {
			return c.Status(400).JSON(fiber.Map{"message": "ชื่อผู้ใช้งานนี้มีอยู่ในระบบแล้ว"})
		}

		// เข้ารหัสรหัสผ่านก่อนลงฐานข้อมูล เพื่อความปลอดภัย
		hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
		if err != nil {
			return c.Status(500).JSON(fiber.Map{"message": "เกิดข้อผิดพลาดในการเข้ารหัสผ่าน"})
		}

		newUser := User{
			Username:   input.Username,
			Password:   string(hashedPassword),
			FullName:   input.FullName,
			Department: input.Department,
			Position:   input.Position,
			Role:       input.Role,
		}

		if err := DB.Create(&newUser).Error; err != nil {
			return c.Status(500).JSON(fiber.Map{"message": "ไม่สามารถบันทึกพนักงานใหม่ได้"})
		}

		return c.Status(201).JSON(fiber.Map{"message": "เพิ่มพนักงานใหม่เข้าสู่ระบบไทคูณสำเร็จแล้ว!"})
	})

	// 🏢 --- [ADMIN FEATURE] API สำหรับจัดการสังกัดแผนก ---
	app.Get("/api/departments", func(c *fiber.Ctx) error {
		var depts []Department
		DB.Order("name asc").Find(&depts)
		return c.JSON(depts)
	})

	app.Post("/api/departments", func(c *fiber.Ctx) error {
		type CreateDeptInput struct {
			Name string `json:"name"`
		}
		var input CreateDeptInput
		if err := c.BodyParser(&input); err != nil || input.Name == "" {
			return c.Status(400).JSON(fiber.Map{"message": "กรุณาระบุชื่อแผนกให้ถูกต้อง"})
		}

		var existing Department
		if err := DB.Where("name = ?", input.Name).First(&existing).Error; err == nil {
			return c.Status(400).JSON(fiber.Map{"message": "แผนกนี้มีอยู่ในระบบแล้ว"})
		}

		newDept := Department{Name: input.Name}
		if err := DB.Create(&newDept).Error; err != nil {
			return c.Status(500).JSON(fiber.Map{"message": "ไม่สามารถเพิ่มสังกัดแผนกได้"})
		}
		return c.Status(201).JSON(fiber.Map{"message": "เพิ่มสังกัดแผนกสำเร็จแล้ว!"})
	})

	app.Delete("/api/departments/:id", func(c *fiber.Ctx) error {
		id := c.Params("id")

		var dept Department
		if err := DB.First(&dept, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบสังกัดแผนกนี้ในระบบ"})
		}

		var usingCount int64
		DB.Model(&User{}).Where("department = ?", dept.Name).Count(&usingCount)
		if usingCount > 0 {
			return c.Status(400).JSON(fiber.Map{"message": fmt.Sprintf("ไม่สามารถลบได้ เนื่องจากมีพนักงาน %d คนสังกัดแผนกนี้อยู่", usingCount)})
		}

		DB.Delete(&dept)
		return c.JSON(fiber.Map{"message": "ลบสังกัดแผนกสำเร็จแล้ว!"})
	})

	// 🔑 --- [ADMIN FEATURE] API สำหรับให้ Admin รีเซ็ตรหัสผ่านของพนักงานคนใดก็ได้ ---
	app.Patch("/api/users/:id/reset-password", func(c *fiber.Ctx) error {
		id := c.Params("id")

		type ResetPasswordInput struct {
			NewPassword string `json:"new_password"`
		}
		var input ResetPasswordInput
		if err := c.BodyParser(&input); err != nil {
			return c.Status(400).JSON(fiber.Map{"message": "ข้อมูลไม่ถูกต้อง"})
		}

		if len(input.NewPassword) < 6 {
			return c.Status(400).JSON(fiber.Map{"message": "รหัสผ่านใหม่ต้องมีความยาวอย่างน้อย 6 ตัวอักษร"})
		}

		var targetUser User
		if err := DB.First(&targetUser, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบผู้ใช้งานนี้ในระบบ"})
		}

		hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.NewPassword), bcrypt.DefaultCost)
		if err != nil {
			return c.Status(500).JSON(fiber.Map{"message": "เกิดข้อผิดพลาดในการเข้ารหัสผ่าน"})
		}

		DB.Model(&targetUser).Update("password", string(hashedPassword))

		return c.JSON(fiber.Map{"message": fmt.Sprintf("รีเซ็ตรหัสผ่านของ %s สำเร็จแล้ว!", targetUser.FullName)})
	})

	// ✏️ --- [ADMIN FEATURE] API สำหรับให้ Admin แก้ไขข้อมูลพนักงาน ---
	app.Put("/api/users/:id", func(c *fiber.Ctx) error {
		id := c.Params("id")

		type EditUserInput struct {
			Username   string `json:"username"`
			FullName   string `json:"full_name"`
			Department string `json:"department"`
			Position   string `json:"position"`
			Role       string `json:"role"`
			AdminName  string `json:"admin_name"` // ชื่อ admin ที่ส่งมาจาก frontend
		}
		var input EditUserInput
		if err := c.BodyParser(&input); err != nil {
			return c.Status(400).JSON(fiber.Map{"message": "ข้อมูลไม่ถูกต้อง"})
		}

		var targetUser User
		if err := DB.First(&targetUser, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบผู้ใช้งานนี้ในระบบ"})
		}

		// เช็คว่า username ใหม่ซ้ำกับคนอื่นไหม (ยกเว้นตัวเอง)
		if input.Username != targetUser.Username {
			var existing User
			if err := DB.Where("username = ? AND id <> ?", input.Username, id).First(&existing).Error; err == nil {
				return c.Status(400).JSON(fiber.Map{"message": "ชื่อผู้ใช้งานนี้มีอยู่ในระบบแล้ว"})
			}
		}

		// ✅ บันทึกว่าฟิลด์ไหนเปลี่ยน
		var changed []string
		oldVal := fmt.Sprintf(`username:%s | full_name:%s | department:%s | position:%s | role:%s`,
			targetUser.Username, targetUser.FullName, targetUser.Department, targetUser.Position, targetUser.Role)
		newVal := fmt.Sprintf(`username:%s | full_name:%s | department:%s | position:%s | role:%s`,
			input.Username, input.FullName, input.Department, input.Position, input.Role)

		if input.Username != targetUser.Username {
			changed = append(changed, "username")
		}
		if input.FullName != targetUser.FullName {
			changed = append(changed, "ชื่อ-นามสกุล")
		}
		if input.Department != targetUser.Department {
			changed = append(changed, "แผนก")
		}
		if input.Position != targetUser.Position {
			changed = append(changed, "ตำแหน่ง")
		}
		if input.Role != targetUser.Role {
			changed = append(changed, "สิทธิ์")
		}

		DB.Model(&targetUser).Updates(map[string]interface{}{
			"username":   input.Username,
			"full_name":  input.FullName,
			"department": input.Department,
			"position":   input.Position,
			"role":       input.Role,
		})

		// บันทึก log เฉพาะเมื่อมีการเปลี่ยนแปลงจริง
		if len(changed) > 0 {
			fieldStr := ""
			for i, f := range changed {
				if i > 0 {
					fieldStr += ", "
				}
				fieldStr += f
			}
			adminName := input.AdminName
			if adminName == "" {
				adminName = "Admin"
			}
			log := UserEditLog{
				TargetUserID:   targetUser.ID,
				TargetUsername: targetUser.Username,
				TargetFullName: targetUser.FullName,
				AdminName:      adminName,
				FieldChanged:   fieldStr,
				OldValue:       oldVal,
				NewValue:       newVal,
				EditedAt:       time.Now().Format("2006-01-02 15:04:05"),
			}
			DB.Create(&log)
		}

		return c.JSON(fiber.Map{"message": "แก้ไขข้อมูลพนักงานสำเร็จแล้ว!"})
	})

	// 📋 --- [ADMIN] API ดูประวัติการแก้ไขของพนักงานคนนั้น ---
	app.Get("/api/users/:id/edit-logs", func(c *fiber.Ctx) error {
		id := c.Params("id")
		var logs []UserEditLog
		DB.Where("target_user_id = ?", id).Order("created_at desc").Find(&logs)
		return c.JSON(logs)
	})

	// 🗑️ --- [ADMIN FEATURE] API สำหรับให้ Admin ลบบัญชีพนักงาน ---
	app.Delete("/api/users/:id", func(c *fiber.Ctx) error {
		id := c.Params("id")

		var targetUser User
		if err := DB.First(&targetUser, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบผู้ใช้งานนี้ในระบบ"})
		}

		if targetUser.Username == "admin01" {
			return c.Status(400).JSON(fiber.Map{"message": "ไม่สามารถลบบัญชี admin01 หลักของระบบได้"})
		}

		DB.Delete(&targetUser)
		return c.JSON(fiber.Map{"message": fmt.Sprintf("ลบบัญชีของ %s สำเร็จแล้ว!", targetUser.FullName)})
	})

	// ดึงเฉพาะคนที่เป็นพนักงานปฏิบัติการ (สำหรับให้หัวหน้าดึงไปมอบหมายงาน)
	app.Get("/api/employees", func(c *fiber.Ctx) error {
		dept := c.Query("department")
		var emps []User
		if dept != "" {
			DB.Where("role = ? AND department = ?", "employee", dept).Find(&emps)
		} else {
			DB.Where("role = ?", "employee").Find(&emps)
		}
		return c.JSON(emps)
	})

	// ดึงรายชื่อพนักงานทั้งหมดในบริษัท (สำหรับให้ Admin ดูรายชื่อรวม)
	app.Get("/api/users", func(c *fiber.Ctx) error {
		var users []User
		DB.Order("id desc").Find(&users)
		return c.JSON(users)
	})

	// API ระบบจัดการงานรายสัปดาห์
	app.Get("/api/tasks", func(c *fiber.Ctx) error {
		empID := c.Query("employee_id")
		var tasks []WeeklyTask
		if empID != "" {
			DB.Where("employee_id = ?", empID).Order("id desc").Find(&tasks)
		} else {
			DB.Order("id desc").Find(&tasks)
		}
		return c.JSON(tasks)
	})

	app.Post("/api/tasks", func(c *fiber.Ctx) error {
		var task WeeklyTask
		if err := c.BodyParser(&task); err != nil {
			return c.Status(400).JSON(fiber.Map{"message": "ข้อมูลไม่ถูกต้อง"})
		}

		// ✅ เช็ควันซ้ำ: ห้ามมีงานที่วันที่ทับซ้อนกันสำหรับพนักงานคนเดียวกัน
		var overlapping WeeklyTask
		err := DB.Where(
			"employee_id = ? AND task_start_date <= ? AND task_end_date >= ?",
			task.EmployeeID, task.TaskEndDate, task.TaskStartDate,
		).First(&overlapping).Error
		if err == nil {
			return c.Status(400).JSON(fiber.Map{"message": fmt.Sprintf("พนักงานคนนี้มีงานซ้ำในช่วงวันที่ดังกล่าวแล้ว (%s ถึง %s)", overlapping.TaskStartDate, overlapping.TaskEndDate)})
		}

		task.TaskStatus = "assigned"
		DB.Create(&task)
		return c.Status(201).JSON(fiber.Map{"message": "จัดสรรงานประจำสัปดาห์เรียบร้อย!"})
	})

	// ✏️ --- [HEAD FEATURE] API แก้ไขรายละเอียดงาน ---
	app.Put("/api/tasks/:id", func(c *fiber.Ctx) error {
		id := c.Params("id")

		type EditTaskInput struct {
			TaskStartDate string `json:"task_start_date"`
			TaskEndDate   string `json:"task_end_date"`
			TaskDetails   string `json:"task_details"`
			WeekRange     string `json:"week_range"`
		}
		var input EditTaskInput
		if err := c.BodyParser(&input); err != nil {
			return c.Status(400).JSON(fiber.Map{"message": "ข้อมูลไม่ถูกต้อง"})
		}

		var task WeeklyTask
		if err := DB.First(&task, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบงานนี้ในระบบ"})
		}

		// ✅ เช็ควันซ้ำ (ยกเว้นตัวเอง)
		var overlapping WeeklyTask
		err := DB.Where(
			"employee_id = ? AND task_start_date <= ? AND task_end_date >= ? AND id <> ?",
			task.EmployeeID, input.TaskEndDate, input.TaskStartDate, id,
		).First(&overlapping).Error
		if err == nil {
			return c.Status(400).JSON(fiber.Map{"message": fmt.Sprintf("มีงานซ้ำในช่วงวันที่ดังกล่าวแล้ว (%s ถึง %s)", overlapping.TaskStartDate, overlapping.TaskEndDate)})
		}

		DB.Model(&task).Updates(map[string]interface{}{
			"task_start_date": input.TaskStartDate,
			"task_end_date":   input.TaskEndDate,
			"task_details":    input.TaskDetails,
			"week_range":      input.WeekRange,
		})
		return c.JSON(fiber.Map{"message": "แก้ไขงานสำเร็จแล้ว!"})
	})

	// 🗑️ --- [HEAD FEATURE] API ลบงาน ---
	app.Delete("/api/tasks/:id", func(c *fiber.Ctx) error {
		id := c.Params("id")

		var task WeeklyTask
		if err := DB.First(&task, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบงานนี้ในระบบ"})
		}

		DB.Delete(&task)
		return c.JSON(fiber.Map{"message": "ลบงานสำเร็จแล้ว!"})
	})

	app.Patch("/api/tasks/:id/status", func(c *fiber.Ctx) error {
		id := c.Params("id")
		type StatusInput struct {
			Status string `json:"status"`
		}
		var input StatusInput
		c.BodyParser(&input)
		DB.Model(&WeeklyTask{}).Where("id = ?", id).Update("task_status", input.Status)
		return c.JSON(fiber.Map{"message": "อัปเดตสถานะงานสำเร็จ!"})
	})

	// 📝 --- [HEAD FEATURE] API ระบบบันทึกความคืบหน้างานรายวัน ---
	app.Get("/api/daily-logs", func(c *fiber.Ctx) error {
		empID := c.Query("employee_id")
		startDate := c.Query("start")
		endDate := c.Query("end")

		query := DB.Model(&DailyLog{})
		if empID != "" {
			query = query.Where("employee_id = ?", empID)
		}
		if startDate != "" && endDate != "" {
			query = query.Where("log_date >= ? AND log_date <= ?", startDate, endDate)
		}

		var logs []DailyLog
		query.Order("log_date asc").Find(&logs)
		return c.JSON(logs)
	})

	app.Post("/api/daily-logs", func(c *fiber.Ctx) error {
		type CreateLogInput struct {
			EmployeeID   uint   `json:"employee_id"`
			EmployeeName string `json:"employee_name"`
			LogDate      string `json:"log_date"`
			Note         string `json:"note"`
			CreatedBy    string `json:"created_by"`
		}
		var input CreateLogInput
		if err := c.BodyParser(&input); err != nil || input.Note == "" || input.LogDate == "" {
			return c.Status(400).JSON(fiber.Map{"message": "กรุณากรอกข้อมูลบันทึกให้ถูกต้อง"})
		}

		// เช็คว่ามีบันทึกของพนักงานคนนี้ในวันนี้อยู่แล้วไหม ถ้ามีให้แก้ไขทับ ไม่สร้างซ้ำ
		var existing DailyLog
		err := DB.Where("employee_id = ? AND log_date = ?", input.EmployeeID, input.LogDate).First(&existing).Error
		if err == nil {
			DB.Model(&existing).Update("note", input.Note)
			return c.JSON(fiber.Map{"message": "อัปเดตบันทึกความคืบหน้าสำเร็จแล้ว!"})
		}

		newLog := DailyLog{
			EmployeeID:   input.EmployeeID,
			EmployeeName: input.EmployeeName,
			LogDate:      input.LogDate,
			Note:         input.Note,
			CreatedBy:    input.CreatedBy,
		}
		if err := DB.Create(&newLog).Error; err != nil {
			return c.Status(500).JSON(fiber.Map{"message": "ไม่สามารถบันทึกความคืบหน้าได้"})
		}
		return c.Status(201).JSON(fiber.Map{"message": "บันทึกความคืบหน้าสำเร็จแล้ว!"})
	})

	app.Delete("/api/daily-logs/:id", func(c *fiber.Ctx) error {
		id := c.Params("id")

		var logEntry DailyLog
		if err := DB.First(&logEntry, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบบันทึกนี้ในระบบ"})
		}

		DB.Delete(&logEntry)
		return c.JSON(fiber.Map{"message": "ลบบันทึกสำเร็จแล้ว!"})
	})

	// 🚜 --- [MACHINE FEATURE] API จัดการเครื่องจักร ---

	// แอดมินเพิ่มเครื่องจักรใหม่เข้าระบบ
	app.Post("/api/machines", func(c *fiber.Ctx) error {
		type CreateMachineInput struct {
			Name string `json:"name"`
			Code string `json:"code"`
			Type string `json:"type"`
		}
		var input CreateMachineInput
		if err := c.BodyParser(&input); err != nil || input.Name == "" || input.Code == "" {
			return c.Status(400).JSON(fiber.Map{"message": "กรุณากรอกชื่อและรหัสเครื่องจักรให้ถูกต้อง"})
		}

		var existing Machine
		if err := DB.Where("code = ?", input.Code).First(&existing).Error; err == nil {
			return c.Status(400).JSON(fiber.Map{"message": "รหัสเครื่องจักรนี้มีอยู่ในระบบแล้ว"})
		}

		machine := Machine{Name: input.Name, Code: input.Code, Type: input.Type, Status: "available"}
		if err := DB.Create(&machine).Error; err != nil {
			return c.Status(500).JSON(fiber.Map{"message": "ไม่สามารถเพิ่มเครื่องจักรได้"})
		}
		return c.Status(201).JSON(fiber.Map{"message": fmt.Sprintf("เพิ่มเครื่องจักร %s เข้าระบบสำเร็จ!", machine.Name)})
	})

	app.Get("/api/machines", func(c *fiber.Ctx) error {
		var machines []Machine
		DB.Order("id desc").Find(&machines)
		return c.JSON(machines)
	})

	app.Delete("/api/machines/:id", func(c *fiber.Ctx) error {
		id := c.Params("id")
		var machine Machine
		if err := DB.First(&machine, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบเครื่องจักรนี้ในระบบ"})
		}
		var activeCheckout MachineCheckout
		if err := DB.Where("machine_id = ? AND status = ?", machine.ID, "out").First(&activeCheckout).Error; err == nil {
			return c.Status(400).JSON(fiber.Map{"message": "ไม่สามารถลบได้ เครื่องจักรนี้ถูกเบิกใช้งานอยู่"})
		}
		DB.Delete(&machine)
		return c.JSON(fiber.Map{"message": fmt.Sprintf("ลบเครื่องจักร %s สำเร็จแล้ว!", machine.Name)})
	})

	// เจ้าหน้าที่เครื่องจักรลงบันทึกการเบิกเครื่องออกไปใช้งาน
	app.Post("/api/machine-checkouts", func(c *fiber.Ctx) error {
		type CreateCheckoutInput struct {
			MachineID    uint   `json:"machine_id"`
			JobName      string `json:"job_name"`
			Location     string `json:"location"`
			CheckoutDate string `json:"checkout_date"`
			DueDate      string `json:"due_date"`
			Note         string `json:"note"`
			CreatedBy    string `json:"created_by"`
		}
		var input CreateCheckoutInput
		if err := c.BodyParser(&input); err != nil || input.JobName == "" || input.CheckoutDate == "" || input.DueDate == "" {
			return c.Status(400).JSON(fiber.Map{"message": "กรุณากรอกข้อมูลการเบิกเครื่องจักรให้ครบถ้วน"})
		}

		var machine Machine
		if err := DB.First(&machine, input.MachineID).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบเครื่องจักรนี้ในระบบ"})
		}
		if machine.Status == "in_use" {
			return c.Status(400).JSON(fiber.Map{"message": fmt.Sprintf("เครื่องจักร %s ถูกเบิกใช้งานอยู่แล้ว", machine.Name)})
		}

		checkout := MachineCheckout{
			MachineID:    machine.ID,
			MachineName:  machine.Name,
			JobName:      input.JobName,
			Location:     input.Location,
			CheckoutDate: input.CheckoutDate,
			DueDate:      input.DueDate,
			Status:       "out",
			Note:         input.Note,
			CreatedBy:    input.CreatedBy,
		}
		if err := DB.Create(&checkout).Error; err != nil {
			return c.Status(500).JSON(fiber.Map{"message": "ไม่สามารถบันทึกการเบิกเครื่องจักรได้"})
		}
		DB.Model(&machine).Update("status", "in_use")
		return c.Status(201).JSON(fiber.Map{"message": fmt.Sprintf("บันทึกการเบิก %s ออกไปใช้งานสำเร็จแล้ว!", machine.Name)})
	})

	// ดึงรายการบันทึกเบิก-คืนเครื่องจักรทั้งหมด (ใช้ทำตารางรายสัปดาห์)
	app.Get("/api/machine-checkouts", func(c *fiber.Ctx) error {
		machineID := c.Query("machine_id")
		var logs []MachineCheckout
		if machineID != "" {
			DB.Where("machine_id = ?", machineID).Order("id desc").Find(&logs)
		} else {
			DB.Order("id desc").Find(&logs)
		}
		return c.JSON(logs)
	})

	// เจ้าหน้าที่เครื่องจักรลงบันทึกการรับเครื่องคืน
	app.Patch("/api/machine-checkouts/:id/return", func(c *fiber.Ctx) error {
		id := c.Params("id")
		var checkout MachineCheckout
		if err := DB.First(&checkout, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบบันทึกการเบิกเครื่องจักรนี้"})
		}

		type ReturnInput struct {
			ReturnedDate string `json:"returned_date"`
		}
		var input ReturnInput
		c.BodyParser(&input)
		if input.ReturnedDate == "" {
			input.ReturnedDate = time.Now().Format("2006-01-02")
		}

		DB.Model(&checkout).Updates(map[string]interface{}{
			"status":        "returned",
			"returned_date": input.ReturnedDate,
		})
		DB.Model(&Machine{}).Where("id = ?", checkout.MachineID).Update("status", "available")
		return c.JSON(fiber.Map{"message": "บันทึกการคืนเครื่องจักรสำเร็จแล้ว!"})
	})

	// แก้ไขรายละเอียดการเบิก (เช่น เลื่อนกำหนดคืน, แก้ไขสถานที่/งาน)
	app.Put("/api/machine-checkouts/:id", func(c *fiber.Ctx) error {
		id := c.Params("id")
		var checkout MachineCheckout
		if err := DB.First(&checkout, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบบันทึกการเบิกเครื่องจักรนี้"})
		}

		type EditCheckoutInput struct {
			JobName      string `json:"job_name"`
			Location     string `json:"location"`
			CheckoutDate string `json:"checkout_date"`
			DueDate      string `json:"due_date"`
			Note         string `json:"note"`
		}
		var input EditCheckoutInput
		if err := c.BodyParser(&input); err != nil {
			return c.Status(400).JSON(fiber.Map{"message": "ข้อมูลไม่ถูกต้อง"})
		}

		DB.Model(&checkout).Updates(map[string]interface{}{
			"job_name":      input.JobName,
			"location":      input.Location,
			"checkout_date": input.CheckoutDate,
			"due_date":      input.DueDate,
			"note":          input.Note,
		})
		return c.JSON(fiber.Map{"message": "แก้ไขข้อมูลการเบิกเครื่องจักรสำเร็จแล้ว!"})
	})

	// ลบบันทึกการเบิก (กรณีลงข้อมูลผิด) — คืนสถานะเครื่องเป็นพร้อมใช้งานถ้ายังไม่คืน
	app.Delete("/api/machine-checkouts/:id", func(c *fiber.Ctx) error {
		id := c.Params("id")
		var checkout MachineCheckout
		if err := DB.First(&checkout, id).Error; err != nil {
			return c.Status(404).JSON(fiber.Map{"message": "ไม่พบบันทึกการเบิกเครื่องจักรนี้"})
		}
		if checkout.Status == "out" {
			DB.Model(&Machine{}).Where("id = ?", checkout.MachineID).Update("status", "available")
		}
		DB.Delete(&checkout)
		return c.JSON(fiber.Map{"message": "ลบบันทึกการเบิกเครื่องจักรสำเร็จแล้ว!"})
	})

	log.Fatal(app.Listen("0.0.0.0:8080"))
}
