package handlers

import (
	"bytes"
	"cangui/whatsapp/backend/jwt"
	"cangui/whatsapp/backend/models"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"time"

	"github.com/gorilla/mux"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

// Simuler un SSO + Redirection selon rôle
func LoginHandler(db *gorm.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        

        var reqUser models.User
        if err := json.NewDecoder(r.Body).Decode(&reqUser); err != nil {
            http.Error(w, "Bad request", http.StatusBadRequest)
            return
        }

        var user models.User
        result := db.Where("email = ?", reqUser.Email).First(&user)
        if result.Error != nil {
            http.Error(w, "Invalid credentials", http.StatusUnauthorized)
            return
        }

        // Vérification du mot de passe hashé
        if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(reqUser.Password)); err != nil {
            http.Error(w, "Invalid credentials", http.StatusUnauthorized)
            return
        }

        // Création du JWT
		fmt.Printf("login");
		fmt.Printf(user.SSOID)
        tokenString, err := jwt.CreateToken(user.SSOID)
        if err != nil {
            http.Error(w, "Internal error", http.StatusInternalServerError)
            return
        }

        // Cookie HTTP-only
        http.SetCookie(w, &http.Cookie{
            Name:     "token",
            Value:    tokenString,
            Path:     "/",
            HttpOnly: true,
            Secure:   false, // à mettre à true en prod HTTPS
            SameSite: http.SameSiteLaxMode,
        })

        // HX-Redirect pour HTMX
        w.Header().Set("HX-Redirect", "/dashboard")
        w.WriteHeader(http.StatusOK)
        w.Write([]byte(`{"message":"Login success"}`))
    }
}
func SSOLoginHandler(db *gorm.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        code := r.URL.Query().Get("code")
        var user models.User
        if result := db.Where("sso_id = ?", code).First(&user); result.Error != nil || !user.IsActive {
            http.Error(w, "Invalid SSO code", http.StatusUnauthorized)
            return
        }

        token, err := jwt.CreateToken(user.Email)
        if err != nil {
            http.Error(w, "Token error", http.StatusInternalServerError)
            return
        }

        http.SetCookie(w, &http.Cookie{
            Name:     "token",
            Value:    token,
            Path:     "/",
            HttpOnly: true,
            Secure:   false,
        })

        http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
    }
}
func SendWhatsAppMessage(db *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		val := r.Context().Value("ssoid")
		ssoid, ok := val.(string)
		if !ok || ssoid == "" {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}

		fmt.Println("✅ SSOID reçu depuis le contexte :", ssoid)

		// Récupérer l'utilisateur en base via le SSOID
		var user models.User
		if err := db.Where("sso_id = ?", ssoid).First(&user).Error; err != nil || user.ID == 0 {
			http.Error(w, "Utilisateur introuvable", http.StatusUnauthorized)
			return
		}

		var payload map[string]interface{}
		if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
			http.Error(w, "Invalid JSON", http.StatusBadRequest)
			return
		}

		fmt.Printf("📨 Payload reçu : %+v\n", payload)

		message, err := models.BuildMessageFromPayload(payload)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
			return
		}

		jsonBody, err := json.MarshalIndent(message, "", "  ") // joli format
		if err != nil {
			http.Error(w, "Failed to encode message", http.StatusInternalServerError)
			return
		}

		apiURL := fmt.Sprintf("https://graph.facebook.com/v22.0/%s/messages", user.WhatsappPhoneNumberID)

		fmt.Println("📡 Envoi de la requête à :", apiURL)
		fmt.Println("📦 JSON envoyé :")
		fmt.Println(string(jsonBody))

		req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonBody))
		if err != nil {
			http.Error(w, "Failed to create request", http.StatusInternalServerError)
			return
		}

		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer "+user.WhatsappToken)

		fmt.Println("📋 Headers :")
		for key, vals := range req.Header {
			for _, v := range vals {
				fmt.Printf("  %s: %s\n", key, v)
			}
		}

		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			http.Error(w, "Failed to contact WhatsApp API", http.StatusBadGateway)
			return
		}
		defer resp.Body.Close()

		// 🛠 debug réponse
		respBody, _ := io.ReadAll(resp.Body)
		fmt.Printf("✅ Réponse WhatsApp (%d) : %s\n", resp.StatusCode, string(respBody))

		w.WriteHeader(resp.StatusCode)
		w.Write(respBody)
	}
}

var MessageTypeCreditCost = map[string]uint{
	"text":       1,
	"image":      2,
	"video":      2,
	"audio":      1,
	"document":   2,
	"sticker":    1,
	"interactive": 1,
	"reaction":   0,
	"location":   1,
	"contacts":   1,
}
func WebhookHandler(db *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var body map[string]interface{}
		if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
			http.Error(w, "invalid JSON", http.StatusBadRequest)
			return
		}

		entry := body["entry"].([]interface{})[0].(map[string]interface{})
		changes := entry["changes"].([]interface{})[0].(map[string]interface{})
		value := changes["value"].(map[string]interface{})

		// Gestion des messages entrants
		if msgs, ok := value["messages"]; ok {
			messages := msgs.([]interface{})
			for _, msg := range messages {
				m := msg.(map[string]interface{})
				waID := value["contacts"].([]interface{})[0].(map[string]interface{})["wa_id"].(string)
				msgID := m["id"].(string)
				typeMsg := m["type"].(string)
				content := extractMessageContent(m)

				var user models.User
				if err := db.Where("sso_id = ?", waID).First(&user).Error; err != nil {
					fmt.Println("Utilisateur non trouvé pour:", waID)
					continue
				}

				db.Create(&models.Conversation{
					UserID:    user.ID,
					From:      waID,
					To:        value["metadata"].(map[string]interface{})["display_phone_number"].(string),
					MessageID: msgID,
					Type:      typeMsg,
					Content:   content,
					Direction: "inbound",
				})

				credit := MessageTypeCreditCost[typeMsg]
				if credit > 0 {
					ConsumeCredits(db, &user, typeMsg, content, credit)
				}
			}
		}

		// Gestion des statuts (delivered, read, etc.)
		if statuses, ok := value["statuses"]; ok {
			for _, s := range statuses.([]interface{}) {
				status := s.(map[string]interface{})
				msgID := status["id"].(string)
				state := status["status"].(string)
				db.Model(&models.Conversation{}).Where("message_id = ?", msgID).Update("status", state)
			}
		}

		w.WriteHeader(http.StatusOK)
	}
}
func extractMessageContent(m map[string]interface{}) string {
	t := m["type"].(string)
	switch t {
	case "text":
		return m["text"].(map[string]interface{})["body"].(string)
	case "image", "video", "audio", "document", "sticker":
		return m[t].(map[string]interface{})["id"].(string)
	case "interactive":
		return m[t].(map[string]interface{})["type"].(string)
	default:
		return "[non textuel]"
	}
}
func ConsumeCredits(db *gorm.DB, user *models.User, messageType, content string, credits uint) {
	user.CurrentMonthCredits -= credits
	db.Save(user)

	db.Create(&models.Consumption{
		UserID:      user.ID,
		MessageType: messageType,
		Description: content,
		CreditsUsed: credits,
	})

	month := time.Now().Format("2006-01")
	var mc models.MonthlyConsumption
	db.Where("user_id = ? AND month = ?", user.ID, month).FirstOrInit(&mc)
	mc.UserID = user.ID
	mc.Month = month
	mc.TotalUsed += credits
	db.Save(&mc)
}
func GetUserConversations(db *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		userID, err := strconv.Atoi(mux.Vars(r)["id"])
		if err != nil {
			http.Error(w, "Invalid user ID", http.StatusBadRequest)
			return
		}

		var conversations []models.Conversation
		if err := db.Where("user_id = ?", userID).
			Order("created_at desc").
			Find(&conversations).Error; err != nil {
			http.Error(w, "Error retrieving conversations", http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(conversations)
	}
}
// WebhookVerifyHandler répond au GET initial de vérification Meta
func WebhookVerifyHandler() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		mode := r.URL.Query().Get("hub.mode")
		token := r.URL.Query().Get("hub.verify_token")
		challenge := r.URL.Query().Get("hub.challenge")

		if mode == "subscribe" && token == "secrettoken" {
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(challenge))
			return
		}

		w.WriteHeader(http.StatusForbidden)
		w.Write([]byte("Invalid verify token"))
	}
}
func WebhookReceiveHandler(db *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var body map[string]interface{}
		if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
			http.Error(w, "Invalid JSON", http.StatusBadRequest)
			return
		}

		fmt.Println("📩 Webhook reçu :", body)

		// Exemple de parsing
		entry := body["entry"].([]interface{})[0].(map[string]interface{})
		change := entry["changes"].([]interface{})[0].(map[string]interface{})
		value := change["value"].(map[string]interface{})

		messages := value["messages"].([]interface{})
		if len(messages) > 0 {
			msg := messages[0].(map[string]interface{})
			from := msg["from"].(string)
			msgType := msg["type"].(string)

			var content string
			if msgType == "text" {
				content = msg["text"].(map[string]interface{})["body"].(string)
			}

			fmt.Printf("💬 Message reçu de %s : %s\n", from, content)

			// TODO : enregistrer en base
		}

		w.WriteHeader(http.StatusOK)
	}
}

func CreateUser(db *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var user models.User
		if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
			http.Error(w, "Invalid JSON", http.StatusBadRequest)
			return
		}

		hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
		if err != nil {
			http.Error(w, "Hash error", http.StatusInternalServerError)
			return
		}
		user.Password = string(hash)

		if err := db.Create(&user).Error; err != nil {
			http.Error(w, "Create failed", http.StatusInternalServerError)
			return
		}
		json.NewEncoder(w).Encode(user)
	}
}

func GetAllUsers(db *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var users []models.User
		db.Find(&users)
		json.NewEncoder(w).Encode(users)
	}
}

func GetUserByID(db *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id, _ := strconv.Atoi(mux.Vars(r)["id"])
		var user models.User
		if err := db.First(&user, id).Error; err != nil {
			http.Error(w, "Not found", http.StatusNotFound)
			return
		}
		json.NewEncoder(w).Encode(user)
	}
}

func UpdateUser(db *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id, _ := strconv.Atoi(mux.Vars(r)["id"])
		var user models.User
		if err := db.First(&user, id).Error; err != nil {
			http.Error(w, "Not found", http.StatusNotFound)
			return
		}
		var input models.User
		if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
			http.Error(w, "Invalid JSON", http.StatusBadRequest)
			return
		}
		if input.Password != "" {
			hash, _ := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
			input.Password = string(hash)
		} else {
			input.Password = user.Password
		}
		input.ID = user.ID
		if err := db.Model(&user).Updates(input).Error; err != nil {
			http.Error(w, "Update failed", http.StatusInternalServerError)
			return
		}
		json.NewEncoder(w).Encode(user)
	}
}

func DeleteUser(db *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id, _ := strconv.Atoi(mux.Vars(r)["id"])
		if err := db.Delete(&models.User{}, id).Error; err != nil {
			http.Error(w, "Delete failed", http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusNoContent)
	}
}

func HandleTemplateTest(db *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		val := r.Context().Value("ssoid")
		ssoid, ok := val.(string)
		if !ok || ssoid == "" {
			http.Error(w, "Non authentifié", http.StatusUnauthorized)
			return
		}

		if err := r.ParseForm(); err != nil {
			http.Error(w, "Form invalide", http.StatusBadRequest)
			return
		}

		to := r.FormValue("to")
		templateName := r.FormValue("template_name")
		lang := r.FormValue("language")

		var params []string
		for i := 1; i <= 5; i++ {
			val := r.FormValue(fmt.Sprintf("param%d", i))
			if val != "" {
				params = append(params, val)
			}
		}

		var user models.User
		if err := db.Where("sso_id = ?", ssoid).First(&user).Error; err != nil || user.ID == 0 {
			http.Error(w, "Utilisateur introuvable", http.StatusUnauthorized)
			return
		}

		message := models.NewTemplateMessage(to, templateName, lang, params)
		jsonBody, _ := json.MarshalIndent(message, "", "  ")

		apiURL := fmt.Sprintf("https://graph.facebook.com/v22.0/%s/messages", user.WhatsappPhoneNumberID)
		req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonBody))
		if err != nil {
			http.Error(w, "Requête WhatsApp échouée", http.StatusInternalServerError)
			return
		}

		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer "+user.WhatsappToken)

		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			http.Error(w, "Échec de l'appel API WhatsApp", http.StatusBadGateway)
			return
		}
		defer resp.Body.Close()

		io.Copy(w, resp.Body)
	}
}
