package handlers

import (
	"crypto/rand"
	"encoding/json"
	"fmt"
	"furry-sos-backend/config"
	"math/big"
	"net/http"
	"net/smtp"
	"os"
	"strconv"
	"strings"
	"time"
)

type RegisterRequest struct {
	Username string `json:"username"`
	FullName string `json:"full_name"`
	Email    string `json:"email"`
	Phone    string `json:"phone"`
	Password string `json:"password"`
	Role     string `json:"role"`
}

func Register(w http.ResponseWriter, r *http.Request) {

	if r.Method != http.MethodPost {
		http.Error(
			w,
			"Method not allowed",
			http.StatusMethodNotAllowed,
		)
		return
	}

	var req RegisterRequest

	err := json.NewDecoder(r.Body).Decode(&req)

	if err != nil {
		http.Error(
			w,
			"Invalid request body",
			http.StatusBadRequest,
		)
		return
	}

	// ==========================================
	// ตรวจ Role
	// ==========================================

	if req.Role == "" {
		req.Role = "user"
	}

	if req.Role != "user" &&
		req.Role != "volunteer" {

		http.Error(
			w,
			"ประเภทบัญชีไม่ถูกต้อง",
			http.StatusBadRequest,
		)

		return
	}

	// ==========================================
	// ตรวจข้อมูลเบื้องต้น
	// ==========================================

	if req.Username == "" ||
		req.FullName == "" ||
		req.Email == "" ||
		req.Phone == "" ||
		req.Password == "" {

		http.Error(
			w,
			"กรุณากรอกข้อมูลให้ครบถ้วน",
			http.StatusBadRequest,
		)

		return
	}

	// ==========================================
	// ตรวจ Username / Email ซ้ำ
	// ==========================================

	var count int

	err = config.DB.QueryRow(
		`
		SELECT COUNT(*)
		FROM users
		WHERE username = ? OR email = ?
		`,
		req.Username,
		req.Email,
	).Scan(&count)

	if err != nil {
		http.Error(
			w,
			"ตรวจสอบข้อมูลไม่สำเร็จ: "+err.Error(),
			http.StatusInternalServerError,
		)

		return
	}

	if count > 0 {
		http.Error(
			w,
			"ชื่อผู้ใช้หรืออีเมลนี้ถูกใช้งานแล้ว",
			http.StatusConflict,
		)

		return
	}

	// ==========================================
	// INSERT USER
	// ==========================================

	query := `
		INSERT INTO users
		(
			username,
			full_name,
			email,
			phone,
			password_hash,
			role
		)
		VALUES
		(
			?,
			?,
			?,
			?,
			?,
			?
		)
	`

	result, err := config.DB.Exec(
		query,
		req.Username,
		req.FullName,
		req.Email,
		req.Phone,
		req.Password,
		req.Role,
	)

	if err != nil {

		http.Error(
			w,
			"สมัครสมาชิกไม่สำเร็จ: "+err.Error(),
			http.StatusInternalServerError,
		)

		return
	}

	userID, err := result.LastInsertId()

	if err != nil {

		http.Error(
			w,
			"ไม่สามารถสร้าง User ID ได้",
			http.StatusInternalServerError,
		)

		return
	}

	// ==========================================
	// RESPONSE
	// ==========================================

	w.Header().Set(
		"Content-Type",
		"application/json; charset=utf-8",
	)

	json.NewEncoder(w).Encode(
		map[string]interface{}{
			"success":   true,
			"message":   "สมัครสมาชิกสำเร็จ!",
			"user_id":   userID,
			"role":      req.Role,
			"full_name": req.FullName,
		},
	)
}

// ======================================================
// LOGIN
// ======================================================

type LoginRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

func Login(w http.ResponseWriter, r *http.Request) {

	if r.Method != http.MethodPost {

		http.Error(
			w,
			"Method not allowed",
			http.StatusMethodNotAllowed,
		)

		return
	}

	var req LoginRequest

	err := json.NewDecoder(r.Body).Decode(&req)

	if err != nil {

		http.Error(
			w,
			"Invalid request body",
			http.StatusBadRequest,
		)

		return
	}

	// ==========================================
	// GET USER
	// ==========================================

	var userID int
	var fullName string
	var passwordHash string
	var role string

	query := `
		SELECT
			user_id,
			full_name,
			password_hash,
			role
		FROM users
		WHERE username = ? OR email = ?
	`

	err = config.DB.QueryRow(
		query,
		req.Username,
		req.Username,
	).Scan(
		&userID,
		&fullName,
		&passwordHash,
		&role,
	)

	if err != nil {

		http.Error(
			w,
			"❌ ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง",
			http.StatusUnauthorized,
		)

		return
	}

	// ==========================================
	// CHECK PASSWORD
	// ==========================================

	if passwordHash != req.Password {

		http.Error(
			w,
			"❌ ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง",
			http.StatusUnauthorized,
		)

		return
	}

	// ==========================================
	// DEFAULT ROLE
	// ==========================================

	if role == "" {
		role = "user"
	}

	// ==========================================
	// RESPONSE
	// ==========================================

	w.Header().Set(
		"Content-Type",
		"application/json; charset=utf-8",
	)

	json.NewEncoder(w).Encode(
		map[string]interface{}{
			"success":   true,
			"message":   "เข้าสู่ระบบสำเร็จ!",
			"user_id":   userID,
			"full_name": fullName,
			"role":      role,
			"token":     "fake-token-12345",
		},
	)
}

// ======================================================
// FORGOT PASSWORD - SEND OTP
// POST /api/forgot-password
// ======================================================

type ForgotPasswordRequest struct {
	Email string `json:"email"`
}

func ForgotPassword(w http.ResponseWriter, r *http.Request) {

	if r.Method != http.MethodPost {
		http.Error(
			w,
			"Method not allowed",
			http.StatusMethodNotAllowed,
		)
		return
	}

	var req ForgotPasswordRequest

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(
			w,
			"Invalid request body",
			http.StatusBadRequest,
		)
		return
	}

	req.Email = strings.TrimSpace(req.Email)

	if req.Email == "" {
		http.Error(
			w,
			"กรุณากรอกอีเมล",
			http.StatusBadRequest,
		)
		return
	}

	_, err := config.DB.Exec(`
		CREATE TABLE IF NOT EXISTS password_reset_otps (
			id INT AUTO_INCREMENT PRIMARY KEY,
			user_id INT NOT NULL,
			email VARCHAR(255) NOT NULL,
			otp VARCHAR(6) NOT NULL,
			expires_at DATETIME NOT NULL,
			used BOOLEAN DEFAULT FALSE,
			created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
			INDEX idx_reset_email (email),
			INDEX idx_reset_user (user_id)
		)
	`)

	if err != nil {
		http.Error(
			w,
			"สร้างระบบ OTP ไม่สำเร็จ: "+err.Error(),
			http.StatusInternalServerError,
		)
		return
	}

	var userID int
	var email string

	err = config.DB.QueryRow(`
		SELECT
			user_id,
			email
		FROM users
		WHERE email = ?
		LIMIT 1
	`, req.Email).Scan(&userID, &email)

	if err != nil {
		w.Header().Set(
			"Content-Type",
			"application/json; charset=utf-8",
		)

		json.NewEncoder(w).Encode(
			map[string]interface{}{
				"success": true,
				"message": "หากอีเมลนี้มีอยู่ในระบบ จะได้รับรหัส OTP",
			},
		)
		return
	}

	n, err := rand.Int(rand.Reader, big.NewInt(1000000))
	if err != nil {
		http.Error(
			w,
			"สร้าง OTP ไม่สำเร็จ",
			http.StatusInternalServerError,
		)
		return
	}

	otp := fmt.Sprintf("%06d", n.Int64())
	expiresAt := time.Now().Add(10 * time.Minute)

	_, _ = config.DB.Exec(`
		UPDATE password_reset_otps
		SET used = TRUE
		WHERE user_id = ?
		  AND used = FALSE
	`, userID)

	_, err = config.DB.Exec(`
		INSERT INTO password_reset_otps
		(
			user_id,
			email,
			otp,
			expires_at,
			used
		)
		VALUES (?, ?, ?, ?, FALSE)
	`, userID, email, otp, expiresAt)

	if err != nil {
		http.Error(
			w,
			"บันทึก OTP ไม่สำเร็จ: "+err.Error(),
			http.StatusInternalServerError,
		)
		return
	}

	err = sendResetOTPEmail(email, otp)
	if err != nil {
		_, _ = config.DB.Exec(`
			UPDATE password_reset_otps
			SET used = TRUE
			WHERE user_id = ?
			  AND otp = ?
		`, userID, otp)

		http.Error(
			w,
			"ไม่สามารถส่ง OTP ไปยังอีเมลได้: "+err.Error(),
			http.StatusInternalServerError,
		)
		return
	}

	w.Header().Set(
		"Content-Type",
		"application/json; charset=utf-8",
	)

	json.NewEncoder(w).Encode(
		map[string]interface{}{
			"success":    true,
			"message":    "ส่งรหัส OTP ไปยังอีเมลเรียบร้อยแล้ว",
			"expires_in": 600,
		},
	)
}

// ======================================================
// SEND RESET OTP EMAIL
// ======================================================

func sendResetOTPEmail(toEmail string, otp string) error {

	host := os.Getenv("SMTP_HOST")
	port := os.Getenv("SMTP_PORT")
	username := os.Getenv("SMTP_USERNAME")
	password := os.Getenv("SMTP_PASSWORD")
	from := os.Getenv("SMTP_FROM")

	if host == "" ||
		port == "" ||
		username == "" ||
		password == "" ||
		from == "" {
		return fmt.Errorf("ยังไม่ได้ตั้งค่า SMTP ในไฟล์ .env")
	}

	portInt, err := strconv.Atoi(port)
	if err != nil {
		return fmt.Errorf("SMTP_PORT ไม่ถูกต้อง")
	}

	subject := "Furry SOS - รหัส OTP สำหรับรีเซ็ตรหัสผ่าน"

	body := fmt.Sprintf(
		"สวัสดี\n\n"+
			"มีการขอรีเซ็ตรหัสผ่านสำหรับบัญชี Furry SOS\n\n"+
			"รหัส OTP ของคุณคือ: %s\n\n"+
			"รหัสนี้ใช้ได้ภายใน 10 นาที\n\n"+
			"หากคุณไม่ได้เป็นผู้ขอ กรุณาเพิกเฉยต่ออีเมลนี้",
		otp,
	)

	message := []byte(
		"From: " + from + "\r\n" +
			"To: " + toEmail + "\r\n" +
			"Subject: " + subject + "\r\n" +
			"Content-Type: text/plain; charset=UTF-8\r\n" +
			"\r\n" +
			body,
	)

	auth := smtp.PlainAuth(
		"",
		username,
		password,
		host,
	)

	return smtp.SendMail(
		fmt.Sprintf("%s:%d", host, portInt),
		auth,
		from,
		[]string{toEmail},
		message,
	)
}

// ======================================================
// RESET PASSWORD
// POST /api/reset-password
// ======================================================

type ResetPasswordRequest struct {
	Email       string `json:"email"`
	OTP         string `json:"otp"`
	NewPassword string `json:"new_password"`
}

func ResetPassword(w http.ResponseWriter, r *http.Request) {

	if r.Method != http.MethodPost {
		http.Error(
			w,
			"Method not allowed",
			http.StatusMethodNotAllowed,
		)
		return
	}

	var req ResetPasswordRequest

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(
			w,
			"Invalid request body",
			http.StatusBadRequest,
		)
		return
	}

	req.Email = strings.TrimSpace(req.Email)
	req.OTP = strings.TrimSpace(req.OTP)
	req.NewPassword = strings.TrimSpace(req.NewPassword)

	if req.Email == "" ||
		req.OTP == "" ||
		req.NewPassword == "" {
		http.Error(
			w,
			"กรุณากรอกข้อมูลให้ครบถ้วน",
			http.StatusBadRequest,
		)
		return
	}

	if len(req.NewPassword) < 6 {
		http.Error(
			w,
			"รหัสผ่านใหม่ต้องมีอย่างน้อย 6 ตัวอักษร",
			http.StatusBadRequest,
		)
		return
	}

	var resetID int
	var userID int

	err := config.DB.QueryRow(`
		SELECT
			id,
			user_id
		FROM password_reset_otps
		WHERE email = ?
		  AND otp = ?
		  AND used = FALSE
		  AND expires_at > NOW()
		ORDER BY created_at DESC
		LIMIT 1
	`, req.Email, req.OTP).Scan(&resetID, &userID)

	if err != nil {
		http.Error(
			w,
			"OTP ไม่ถูกต้องหรือหมดอายุแล้ว",
			http.StatusUnauthorized,
		)
		return
	}

	_, err = config.DB.Exec(`
		UPDATE users
		SET password_hash = ?
		WHERE user_id = ?
	`, req.NewPassword, userID)

	if err != nil {
		http.Error(
			w,
			"เปลี่ยนรหัสผ่านไม่สำเร็จ: "+err.Error(),
			http.StatusInternalServerError,
		)
		return
	}

	_, _ = config.DB.Exec(`
		UPDATE password_reset_otps
		SET used = TRUE
		WHERE id = ?
	`, resetID)

	w.Header().Set(
		"Content-Type",
		"application/json; charset=utf-8",
	)

	json.NewEncoder(w).Encode(
		map[string]interface{}{
			"success": true,
			"message": "เปลี่ยนรหัสผ่านสำเร็จ กรุณาเข้าสู่ระบบใหม่",
		},
	)
}
