package handlers

import (
	"bytes"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"furry-sos-backend/config"
	"io"
	"log"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

// ============================================================
// CHAT REQUEST
// ============================================================

type ChatRequest struct {
	UserID    int    `json:"user_id"`
	Question  string `json:"question"`
	Image     []byte `json:"-"`
	ImageType string `json:"-"`
}

// ============================================================
// MAXPLUS REQUEST
// ============================================================

type MaxPlusRequest struct {
	Model     string           `json:"model"`
	MaxTokens int              `json:"max_tokens"`
	System    string           `json:"system"`
	Messages  []MaxPlusMessage `json:"messages"`
	Stream    bool             `json:"stream"`
}

type MaxPlusMessage struct {
	Role    string           `json:"role"`
	Content []MaxPlusContent `json:"content"`
}

type MaxPlusContent struct {
	Type   string              `json:"type,omitempty"`
	Text   string              `json:"text,omitempty"`
	Source *MaxPlusImageSource `json:"source,omitempty"`
}

type MaxPlusImageSource struct {
	Type      string `json:"type"`
	MediaType string `json:"media_type"`
	Data      string `json:"data"`
}

type MaxPlusResponse struct {
	ID         string `json:"id"`
	Type       string `json:"type"`
	Role       string `json:"role"`
	Model      string `json:"model"`
	StopReason string `json:"stop_reason"`

	Content []struct {
		Type string `json:"type"`
		Text string `json:"text"`
	} `json:"content"`

	Error *struct {
		Type    string `json:"type"`
		Message string `json:"message"`
	} `json:"error"`
}

// ============================================================
// AI CHAT HANDLER
// POST /api/chat
// ============================================================

func ChatHandler(w http.ResponseWriter, r *http.Request) {

	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var chatReq ChatRequest

	contentType := r.Header.Get("Content-Type")

	if strings.HasPrefix(contentType, "multipart/form-data") {

		err := r.ParseMultipartForm(10 << 20)

		if err != nil {
			http.Error(w, "ไม่สามารถอ่าน Multipart Form ได้: "+err.Error(), http.StatusBadRequest)
			return
		}

		userIDText := strings.TrimSpace(r.FormValue("user_id"))

		if userIDText == "" {
			http.Error(w, "Missing user_id", http.StatusBadRequest)
			return
		}

		_, err = fmt.Sscanf(userIDText, "%d", &chatReq.UserID)

		if err != nil || chatReq.UserID <= 0 {
			http.Error(w, "user_id ไม่ถูกต้อง", http.StatusBadRequest)
			return
		}

		chatReq.Question = strings.TrimSpace(r.FormValue("question"))

		file, header, err := r.FormFile("image")

		if err == nil {

			defer file.Close()

			imageBytes, readErr := io.ReadAll(file)

			if readErr != nil {
				http.Error(w, "อ่านรูปภาพไม่สำเร็จ: "+readErr.Error(), http.StatusBadRequest)
				return
			}

			if len(imageBytes) == 0 {
				http.Error(w, "ไฟล์รูปภาพว่าง", http.StatusBadRequest)
				return
			}

			imageType := header.Header.Get("Content-Type")

			if imageType == "" || imageType == "application/octet-stream" {
				imageType = http.DetectContentType(imageBytes)
			}

			if imageType == "application/octet-stream" {
				ext := strings.ToLower(filepath.Ext(header.Filename))

				if ext != "" {
					detected := mime.TypeByExtension(ext)

					if detected != "" {
						imageType = detected
					}
				}
			}

			if !strings.HasPrefix(imageType, "image/") {
				http.Error(w, "ไฟล์ที่ส่งมาไม่ใช่รูปภาพ", http.StatusBadRequest)
				return
			}

			chatReq.Image = imageBytes
			chatReq.ImageType = imageType

			log.Println("IMAGE RECEIVED")
			log.Println("Filename =", header.Filename)
			log.Println("Size =", len(imageBytes))
			log.Println("Type =", imageType)

		} else if err != http.ErrMissingFile {
			http.Error(w, "อ่านรูปภาพไม่สำเร็จ: "+err.Error(), http.StatusBadRequest)
			return
		}

		if chatReq.Question == "" && len(chatReq.Image) == 0 {
			http.Error(w, "กรุณาส่ง question หรือ image อย่างน้อยหนึ่งอย่าง", http.StatusBadRequest)
			return
		}

	} else {

		err := json.NewDecoder(r.Body).Decode(&chatReq)

		if err != nil {
			http.Error(w, "Invalid JSON: "+err.Error(), http.StatusBadRequest)
			return
		}

		chatReq.Question = strings.TrimSpace(chatReq.Question)

		if chatReq.UserID <= 0 {
			http.Error(w, "Missing user_id", http.StatusBadRequest)
			return
		}

		if chatReq.Question == "" {
			http.Error(w, "Missing question", http.StatusBadRequest)
			return
		}
	}

	if chatReq.UserID <= 0 {
		http.Error(w, "Missing user_id", http.StatusBadRequest)
		return
	}

	if chatReq.Question == "" && len(chatReq.Image) > 0 {
		chatReq.Question = "ช่วยวิเคราะห์ภาพสัตว์เลี้ยงนี้ และแนะนำการดูแลหรือการปฐมพยาบาลเบื้องต้นที่เหมาะสม โดยไม่วินิจฉัยโรคแทนสัตวแพทย์"
	}

	log.Println("======================================")
	log.Println("CHAT REQUEST")
	log.Println("user_id =", chatReq.UserID)
	log.Println("question =", chatReq.Question)
	log.Println("has_image =", len(chatReq.Image) > 0)
	log.Println("======================================")

	answer := getMaxPlusAnswer(chatReq.Question, chatReq.Image, chatReq.ImageType)

	saveChatHistory(chatReq.UserID, chatReq.Question, answer)

	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	json.NewEncoder(w).Encode(map[string]interface{}{
		"answer":    answer,
		"has_image": len(chatReq.Image) > 0,
	})
}

// ============================================================
// MAXPLUS AI
// ============================================================

func getMaxPlusAnswer(question string, image []byte, imageType string) string {

	apiKey := strings.TrimSpace(os.Getenv("MAXPLUS_API_KEY"))

	if apiKey == "" {
		log.Println("MAXPLUS_API_KEY ไม่พบ")
		return "ไม่พบ MAXPLUS_API_KEY ใน Backend"
	}

	model := "claude-sonnet-5"
	url := "https://api.maxplus-ai.cc/v1/messages"

	systemPrompt := `คุณคือ "Furry SOS AI" ผู้ช่วยด้านการปฐมพยาบาลและดูแลสัตว์เลี้ยงของแอป Furry SOS

กฎสำคัญ:
1. ตอบเป็นภาษาไทยเป็นหลัก
2. ให้คำแนะนำเกี่ยวกับสัตว์เลี้ยง
3. ตอบให้ตรงประเด็น
4. เน้นการปฐมพยาบาลเบื้องต้น
5. ห้ามวินิจฉัยโรคแทนสัตวแพทย์
6. ตอบกระชับประมาณ 3-6 ประโยค`

	userContent := []MaxPlusContent{}

	if len(image) > 0 {

		encodedImage := base64.StdEncoding.EncodeToString(image)

		if imageType == "" {
			imageType = http.DetectContentType(image)
		}

		if !strings.HasPrefix(imageType, "image/") {
			imageType = "image/jpeg"
		}

		userContent = append(userContent, MaxPlusContent{
			Type: "image",
			Source: &MaxPlusImageSource{
				Type:      "base64",
				MediaType: imageType,
				Data:      encodedImage,
			},
		})
	}

	userContent = append(userContent, MaxPlusContent{
		Type: "text",
		Text: question,
	})

	requestBody := MaxPlusRequest{
		Model:     model,
		MaxTokens: 600,
		System:    systemPrompt,
		Messages: []MaxPlusMessage{
			{Role: "user", Content: userContent},
		},
		Stream: false,
	}

	jsonBody, err := json.Marshal(requestBody)

	if err != nil {
		return "สร้างข้อมูลสำหรับ AI ไม่สำเร็จ"
	}

	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(jsonBody))

	if err != nil {
		return "สร้าง Request ไปยัง MaxPlus ไม่สำเร็จ"
	}

	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("anthropic-version", "2023-06-01")

	client := &http.Client{Timeout: 60 * time.Second}

	resp, err := client.Do(req)

	if err != nil {
		return "ไม่สามารถเชื่อมต่อ MaxPlus AI ได้"
	}

	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)

	if err != nil {
		return "อ่านข้อมูลจาก MaxPlus ไม่สำเร็จ"
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {

		var errorResponse MaxPlusResponse

		if err := json.Unmarshal(body, &errorResponse); err == nil {
			if errorResponse.Error != nil {
				return fmt.Sprintf("MaxPlus Error: %s", errorResponse.Error.Message)
			}
		}

		return fmt.Sprintf("MaxPlus HTTP Error: %d", resp.StatusCode)
	}

	var result MaxPlusResponse

	err = json.Unmarshal(body, &result)

	if err != nil {
		return "อ่านคำตอบจาก MaxPlus ไม่สำเร็จ"
	}

	if len(result.Content) == 0 {
		return "MaxPlus ไม่ได้ส่งคำตอบกลับมา"
	}

	var answer strings.Builder

	for _, content := range result.Content {
		if content.Type == "text" {
			answer.WriteString(content.Text)
		}
	}

	finalAnswer := strings.TrimSpace(answer.String())

	if finalAnswer == "" {
		return "AI ส่งคำตอบว่างกลับมา"
	}

	return finalAnswer
}

// ============================================================
// SAVE CHAT HISTORY
// ============================================================

func saveChatHistory(userID int, question string, answer string) {

	query := `
		INSERT INTO chat_history (user_id, question, answer, created_at)
		VALUES (?, ?, ?, NOW())
	`

	_, err := config.DB.Exec(query, userID, question, answer)

	if err != nil {
		log.Println("บันทึก Chat History ไม่สำเร็จ:", err)
		return
	}

	log.Println("บันทึก Chat History สำเร็จ")
}

// ======================================================
// SEND CHAT MESSAGE (User-to-User)
// POST /api/chat/send
// ======================================================

func SendChatMessage(w http.ResponseWriter, r *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	if r.Method != http.MethodPost {
		w.WriteHeader(http.StatusMethodNotAllowed)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "Method not allowed",
		})
		return
	}

	senderID, err := getVolunteerUserID(r)

	if err != nil {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "ไม่พบ User ID",
		})
		return
	}

	senderRole, err := getUserRole(senderID)

	if err != nil {
		senderRole = "user"
	}

	var body struct {
		ReportID   int    `json:"report_id"`
		ReportType string `json:"report_type"`
		ReceiverID int    `json:"receiver_id"`
		Message    string `json:"message"`
	}

	err = json.NewDecoder(r.Body).Decode(&body)

	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "ข้อมูลไม่ถูกต้อง",
		})
		return
	}

	body.Message = strings.TrimSpace(body.Message)

	if body.ReportID <= 0 || body.Message == "" {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "ข้อมูลไม่ครบ",
		})
		return
	}

	if body.ReportType == "" {
		body.ReportType = "emergency"
	}

	if body.ReceiverID <= 0 {
		_ = config.DB.QueryRow(
			`SELECT user_id FROM emergency_reports WHERE report_id = ?`,
			body.ReportID,
		).Scan(&body.ReceiverID)
	}

	if body.ReceiverID <= 0 {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "ไม่พบผู้รับข้อความ",
		})
		return
	}

	result, err := config.DB.Exec(
		`
		INSERT INTO chat_messages
		(report_id, report_type, sender_id, sender_role,
		 receiver_id, message, created_at)
		VALUES (?, ?, ?, ?, ?, ?, NOW())
		`,
		body.ReportID, body.ReportType, senderID, senderRole,
		body.ReceiverID, body.Message,
	)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": err.Error(),
		})
		return
	}

	messageID, _ := result.LastInsertId()

	json.NewEncoder(w).Encode(map[string]interface{}{
		"success":    true,
		"message_id": messageID,
		"message":    "ส่งข้อความสำเร็จ",
	})
}

// ======================================================
// GET CHAT MESSAGES
// GET /api/chat/messages?report_id=X&report_type=Y
// ======================================================

func GetChatMessages(w http.ResponseWriter, r *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	if r.Method != http.MethodGet {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	userID, err := getVolunteerUserID(r)

	if err != nil {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "ไม่พบ User ID",
		})
		return
	}

	reportIDStr := r.URL.Query().Get("report_id")
	reportType := r.URL.Query().Get("report_type")

	if reportType == "" {
		reportType = "emergency"
	}

	reportID, err := strconv.Atoi(reportIDStr)

	if err != nil || reportID <= 0 {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "ไม่พบ report_id",
		})
		return
	}

	rows, err := config.DB.Query(
		`
		SELECT
			m.message_id, m.sender_id, m.sender_role, m.receiver_id,
			m.message, m.is_read, m.created_at,
			COALESCE(u.full_name, 'ไม่ระบุชื่อ') AS sender_name,
			COALESCE(u.profile_image, '') AS sender_image
		FROM chat_messages m
		LEFT JOIN users u ON m.sender_id = u.user_id
		WHERE m.report_id = ? AND m.report_type = ?
		ORDER BY m.created_at ASC
		LIMIT 200
		`,
		reportID, reportType,
	)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": err.Error(),
		})
		return
	}

	defer rows.Close()

	messages := []map[string]interface{}{}

	for rows.Next() {
		var (
			messageID, senderID, receiverID              int
			senderRole, message, senderName, senderImage string
			isRead                                       bool
			createdAt                                    interface{}
		)

		err := rows.Scan(
			&messageID, &senderID, &senderRole, &receiverID,
			&message, &isRead, &createdAt,
			&senderName, &senderImage,
		)

		if err != nil {
			continue
		}

		messages = append(messages, map[string]interface{}{
			"message_id":   messageID,
			"sender_id":    senderID,
			"sender_role":  senderRole,
			"receiver_id":  receiverID,
			"message":      message,
			"is_read":      isRead,
			"created_at":   createdAt,
			"sender_name":  senderName,
			"sender_image": senderImage,
			"is_mine":      senderID == userID,
		})
	}

	_, _ = config.DB.Exec(
		`
		UPDATE chat_messages SET is_read = TRUE
		WHERE report_id = ? AND report_type = ?
		AND receiver_id = ? AND is_read = FALSE
		`,
		reportID, reportType, userID,
	)

	json.NewEncoder(w).Encode(map[string]interface{}{
		"success":    true,
		"count":      len(messages),
		"my_user_id": userID,
		"messages":   messages,
	})
}

// ======================================================
// GET CHAT SUMMARY
// GET /api/chat/summary
// ======================================================

func GetChatSummary(w http.ResponseWriter, r *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	userID, err := getVolunteerUserID(r)

	if err != nil {
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	rows, err := config.DB.Query(
		`
		SELECT
			m.report_id, m.report_type,
			MAX(m.created_at) AS last_message_at,
			(
				SELECT message FROM chat_messages
				WHERE report_id = m.report_id AND report_type = m.report_type
				ORDER BY created_at DESC LIMIT 1
			) AS last_message,
			(
				SELECT COUNT(*) FROM chat_messages
				WHERE report_id = m.report_id AND report_type = m.report_type
				AND receiver_id = ? AND is_read = FALSE
			) AS unread_count
		FROM chat_messages m
		WHERE m.sender_id = ? OR m.receiver_id = ?
		GROUP BY m.report_id, m.report_type
		ORDER BY last_message_at DESC
		`,
		userID, userID, userID,
	)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	defer rows.Close()

	summaries := []map[string]interface{}{}

	for rows.Next() {
		var (
			reportID      int
			reportType    string
			lastMessageAt interface{}
			lastMessage   sql.NullString
			unreadCount   int
		)

		err := rows.Scan(&reportID, &reportType, &lastMessageAt, &lastMessage, &unreadCount)

		if err != nil {
			continue
		}

		summaries = append(summaries, map[string]interface{}{
			"report_id":       reportID,
			"report_type":     reportType,
			"last_message":    lastMessage.String,
			"last_message_at": lastMessageAt,
			"unread_count":    unreadCount,
		})
	}

	json.NewEncoder(w).Encode(map[string]interface{}{
		"success": true,
		"count":   len(summaries),
		"chats":   summaries,
	})
}

// ======================================================
// MARK CHAT AS READ
// POST /api/chat/read
// ======================================================

func MarkChatAsRead(w http.ResponseWriter, r *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	if r.Method != http.MethodPost {
		w.WriteHeader(http.StatusMethodNotAllowed)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "Method not allowed",
		})
		return
	}

	var body struct {
		ReportID   int `json:"report_id"`
		ReceiverID int `json:"receiver_id"`
	}

	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "ข้อมูลไม่ถูกต้อง",
		})
		return
	}

	_, err := config.DB.Exec(
		`
		UPDATE chat_messages 
		SET is_read = TRUE 
		WHERE report_id = ? AND receiver_id = ? AND is_read = FALSE
		`,
		body.ReportID, body.ReceiverID,
	)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": err.Error(),
		})
		return
	}

	json.NewEncoder(w).Encode(map[string]interface{}{"success": true})
}

// ======================================================
// GET REPORTER INFO (พร้อมพิกัดแผนที่)
// GET /api/report/reporter?report_id=X&report_type=Y
//
// ✅ ถ้าไม่ส่ง report_type จะ auto-detect
//    (ลอง emergency ก่อน → ถ้าไม่เจอ → fallback ไป deceased)
// ======================================================

func GetReportReporter(w http.ResponseWriter, r *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	if r.Method != http.MethodGet {
		w.WriteHeader(http.StatusMethodNotAllowed)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "Method not allowed",
		})
		return
	}

	reportIDStr := r.URL.Query().Get("report_id")
	reportType := r.URL.Query().Get("report_type")

	reportID, err := strconv.Atoi(reportIDStr)

	if err != nil || reportID <= 0 {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "ไม่พบ report_id",
		})
		return
	}

	var (
		reporterUserID int
		isAnonymous    bool
		lat            sql.NullFloat64
		lng            sql.NullFloat64
		locationAddr   sql.NullString
		found          bool
		actualType     string
	)

	// ==================================================
	// ถ้าระบุ report_type มาตรงๆ → query ตามนั้นเลย
	// ถ้าไม่ระบุ → ลอง emergency ก่อน แล้ว fallback ไป deceased
	// ==================================================

	tryEmergency := reportType == "" || reportType == "emergency"
	tryDeceased := reportType == "" || reportType == "deceased"

	if tryEmergency {
		err = config.DB.QueryRow(
			`
			SELECT 
				user_id, 
				COALESCE(is_anonymous, 0),
				location_lat, 
				location_lng, 
				COALESCE(location_address, '')
			FROM emergency_reports 
			WHERE report_id = ?
			`,
			reportID,
		).Scan(&reporterUserID, &isAnonymous, &lat, &lng, &locationAddr)

		if err == nil {
			found = true
			actualType = "emergency"
		}
	}

	if !found && tryDeceased {
		err = config.DB.QueryRow(
			`
			SELECT 
				user_id, 
				0,
				location_lat, 
				location_lng, 
				COALESCE(location_address, '')
			FROM deceased_reports 
			WHERE report_id = ?
			`,
			reportID,
		).Scan(&reporterUserID, &isAnonymous, &lat, &lng, &locationAddr)

		if err == nil {
			found = true
			actualType = "deceased"
		}
	}

	if !found {
		w.WriteHeader(http.StatusNotFound)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false, "message": "ไม่พบเคสนี้",
		})
		return
	}

	// ==================================================
	// ดึงชื่อ + เบอร์โทร (ถ้าไม่ anonymous)
	// ==================================================
	var fullName, phone string

	if isAnonymous {
		fullName = "ผู้ไม่ประสงค์ออกนาม"
		phone = ""
	} else {
		err = config.DB.QueryRow(
			`
			SELECT 
				COALESCE(full_name, 'ผู้ใช้'), 
				COALESCE(phone, '') 
			FROM users 
			WHERE user_id = ?
			`,
			reporterUserID,
		).Scan(&fullName, &phone)

		if err != nil {
			fullName = "ผู้ใช้"
			phone = ""
		}
	}

	log.Printf("👤 GET REPORTER: report_id=%d type=%s user_id=%d name=%s\n",
		reportID, actualType, reporterUserID, fullName)

	json.NewEncoder(w).Encode(map[string]interface{}{
		"success":          true,
		"report_id":        reportID,
		"report_type":      actualType,
		"user_id":          reporterUserID,
		"full_name":        fullName,
		"phone":            phone,
		"is_anonymous":     isAnonymous,
		"latitude":         lat.Float64,
		"longitude":        lng.Float64,
		"location_address": locationAddr.String,
	})
}