package handlers

import (
	"strconv"
	"strings"
	"time"

	"server/internal/models"

	"github.com/gofiber/fiber/v2"
	"gorm.io/gorm"
)

func normalizeSSID(ssid string) string {
	return strings.TrimSpace(ssid)
}

func ssidKey(ssid string) string {
	return strings.ToLower(strings.TrimSpace(ssid))
}

func normalizeBSSID(bssid string) string {
	var hex []rune
	for _, c := range strings.ToLower(bssid) {
		if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') {
			hex = append(hex, c)
		}
	}
	if len(hex) != 12 {
		return strings.TrimSpace(bssid)
	}
	s := string(hex)
	return s[0:2] + ":" + s[2:4] + ":" + s[4:6] + ":" + s[6:8] + ":" + s[8:10] + ":" + s[10:12]
}

func bssidKey(bssid string) string {
	var hex []rune
	for _, c := range strings.ToLower(bssid) {
		if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') {
			hex = append(hex, c)
		}
	}
	return string(hex)
}

type wifiItemPayload struct {
	SSID  string `json:"ssid"`
	BSSID string `json:"bssid"`
}

// POST /api/student/report-wifi — ghi nhận SSID + BSSID vào kho
func ReportWifiHandler(db *gorm.DB) fiber.Handler {
	return func(c *fiber.Ctx) error {
		var req struct {
			StudentRkID int64  `json:"studentRkId"`
			SSID        string `json:"ssid"`
			BSSID       string `json:"bssid"`
		}
		if err := c.BodyParser(&req); err != nil {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid payload"})
		}
		ssid := normalizeSSID(req.SSID)
		bssid := normalizeBSSID(req.BSSID)
		sKey := ssidKey(ssid)
		bKey := bssidKey(bssid)
		if sKey == "" || bKey == "" || len(bKey) != 12 {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "ssid and valid bssid are required"})
		}

		now := time.Now()
		var row models.WifiPoolEntry
		err := db.Where("bssid_key = ?", bKey).First(&row).Error
		if err == gorm.ErrRecordNotFound {
			row = models.WifiPoolEntry{
				SSID:            ssid,
				SSIDKey:         sKey,
				BSSID:           bssid,
				BSSIDKey:        bKey,
				HitCount:        1,
				LastSeenAt:      now,
				LastStudentRkID: req.StudentRkID,
			}
			if err := db.Create(&row).Error; err != nil {
				return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
			}
		} else if err != nil {
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
		} else {
			row.HitCount++
			row.LastSeenAt = now
			row.SSID = ssid
			row.SSIDKey = sKey
			row.BSSID = bssid
			if req.StudentRkID > 0 {
				row.LastStudentRkID = req.StudentRkID
			}
			if err := db.Save(&row).Error; err != nil {
				return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
			}
		}
		return c.JSON(fiber.Map{"ok": true, "data": row})
	}
}

// GET /api/student/wifi-policy — danh sách điểm phát được phép (theo BSSID)
func GetStudentWifiPolicyHandler(db *gorm.DB) fiber.Handler {
	return func(c *fiber.Ctx) error {
		var rows []models.AcceptedWifi
		if err := db.Where("bssid_key <> '' AND LENGTH(bssid_key) = 12").Order("ssid asc").Find(&rows).Error; err != nil {
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
		}
		items := make([]wifiItemPayload, 0, len(rows))
		for _, r := range rows {
			items = append(items, wifiItemPayload{SSID: r.SSID, BSSID: r.BSSID})
		}
		return c.JSON(fiber.Map{
			"enforce":       len(items) > 0,
			"accepted":      items,
			"acceptedSsids": nil, // legacy — client mới dùng accepted
		})
	}
}

// GET /api/wifi-pool?q=&limit=
func ListWifiPoolHandler(db *gorm.DB) fiber.Handler {
	return func(c *fiber.Ctx) error {
		q := strings.TrimSpace(c.Query("q", ""))
		limit := 50
		if l, err := strconv.Atoi(c.Query("limit", "50")); err == nil && l > 0 && l <= 200 {
			limit = l
		}
		query := db.Model(&models.WifiPoolEntry{}).Where("bssid_key <> '' AND LENGTH(bssid_key) = 12")
		if q != "" {
			like := "%" + q + "%"
			query = query.Where("ssid LIKE ? OR ssid_key LIKE ? OR bssid LIKE ? OR bssid_key LIKE ?", like, like, like, like)
		}
		var rows []models.WifiPoolEntry
		if err := query.Order("hit_count DESC, last_seen_at DESC").Limit(limit).Find(&rows).Error; err != nil {
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
		}
		return c.JSON(fiber.Map{"data": rows, "q": q, "limit": limit})
	}
}

// GET /api/network/accepted-wifis
func ListAcceptedWifisHandler(db *gorm.DB) fiber.Handler {
	return func(c *fiber.Ctx) error {
		var rows []models.AcceptedWifi
		if err := db.Order("ssid asc, bssid asc").Find(&rows).Error; err != nil {
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
		}
		return c.JSON(fiber.Map{"data": rows})
	}
}

// POST /api/network/accepted-wifis — thay toàn bộ danh sách (cần SSID + BSSID)
func SaveAcceptedWifisHandler(db *gorm.DB) fiber.Handler {
	return func(c *fiber.Ctx) error {
		var req struct {
			Items []wifiItemPayload `json:"items"`
		}
		if err := c.BodyParser(&req); err != nil {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid payload"})
		}
		if err := db.Where("1 = 1").Delete(&models.AcceptedWifi{}).Error; err != nil {
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
		}
		now := time.Now()
		count := 0
		seen := map[string]bool{}
		for _, item := range req.Items {
			ssid := normalizeSSID(item.SSID)
			bssid := normalizeBSSID(item.BSSID)
			sKey := ssidKey(ssid)
			bKey := bssidKey(bssid)
			if sKey == "" || bKey == "" || len(bKey) != 12 || seen[bKey] {
				continue
			}
			seen[bKey] = true
			if err := db.Create(&models.AcceptedWifi{
				SSID:      ssid,
				SSIDKey:   sKey,
				BSSID:     bssid,
				BSSIDKey:  bKey,
				CreatedAt: now,
			}).Error; err != nil {
				return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
			}
			count++
		}
		return c.JSON(fiber.Map{"ok": true, "count": count})
	}
}

// POST /api/network/accepted-wifis/add
func AddAcceptedWifiHandler(db *gorm.DB) fiber.Handler {
	return func(c *fiber.Ctx) error {
		var req wifiItemPayload
		if err := c.BodyParser(&req); err != nil {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid payload"})
		}
		ssid := normalizeSSID(req.SSID)
		bssid := normalizeBSSID(req.BSSID)
		sKey := ssidKey(ssid)
		bKey := bssidKey(bssid)
		if sKey == "" || bKey == "" || len(bKey) != 12 {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "ssid and valid bssid are required"})
		}
		row := models.AcceptedWifi{
			SSID:      ssid,
			SSIDKey:   sKey,
			BSSID:     bssid,
			BSSIDKey:  bKey,
			CreatedAt: time.Now(),
		}
		if err := db.Where("bssid_key = ?", bKey).FirstOrCreate(&row).Error; err != nil {
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
		}
		return c.JSON(fiber.Map{"ok": true, "data": row})
	}
}

// DELETE /api/network/accepted-wifis/:id
func DeleteAcceptedWifiHandler(db *gorm.DB) fiber.Handler {
	return func(c *fiber.Ctx) error {
		id, err := strconv.ParseUint(c.Params("id"), 10, 64)
		if err != nil || id == 0 {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid id"})
		}
		if err := db.Delete(&models.AcceptedWifi{}, id).Error; err != nil {
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
		}
		return c.JSON(fiber.Map{"ok": true})
	}
}
