package handlers

import (
	"context"
	"encoding/json"
	"net/http"

	"git.warky.dev/wdevs/whatshooked/pkg/config"
	"git.warky.dev/wdevs/whatshooked/pkg/logging"
	"git.warky.dev/wdevs/whatshooked/pkg/storage"
)

type accountRuntimeStatus struct {
	AccountID   string `json:"account_id"`
	Type        string `json:"type"`
	Status      string `json:"status"`
	Connected   bool   `json:"connected"`
	QRAvailable bool   `json:"qr_available"`
}

type accountConfigWithStatus struct {
	config.WhatsAppConfig
	Status      string `json:"status"`
	Connected   bool   `json:"connected"`
	QRAvailable bool   `json:"qr_available"`
}

func (h *Handlers) getAccountStatusMapFromDB() map[string]accountRuntimeStatus {
	result := map[string]accountRuntimeStatus{}

	db := storage.GetDB()
	if db == nil {
		return result
	}

	type statusRow struct {
		ID          string `bun:"id"`
		AccountType string `bun:"account_type"`
		Status      string `bun:"status"`
	}

	rows := make([]statusRow, 0)
	err := db.NewSelect().
		Table("whatsapp_account").
		Column("id", "account_type", "status").
		Scan(context.Background(), &rows)
	if err != nil {
		logging.Warn("Failed to load account statuses from database", "error", err)
		return result
	}

	for _, row := range rows {
		accountID := row.ID
		status := row.Status
		if status == "" {
			status = "disconnected"
		}
		result[accountID] = accountRuntimeStatus{
			AccountID:   accountID,
			Type:        row.AccountType,
			Status:      status,
			Connected:   status == "connected",
			QRAvailable: status == "pairing",
		}
	}

	return result
}

// Accounts returns the list of all configured WhatsApp accounts
func (h *Handlers) Accounts(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")

	statusByAccountID := h.getAccountStatusMapFromDB()
	accounts := make([]accountConfigWithStatus, 0, len(h.config.WhatsApp))
	for _, account := range h.config.WhatsApp {
		status := accountRuntimeStatus{
			AccountID: account.ID,
			Type:      account.Type,
			Status:    "disconnected",
		}
		if account.Disabled {
			status.Status = "disconnected"
			status.Connected = false
			status.QRAvailable = false
		} else if fromDB, exists := statusByAccountID[account.ID]; exists {
			status = fromDB
		}

		accounts = append(accounts, accountConfigWithStatus{
			WhatsAppConfig: account,
			Status:         status.Status,
			Connected:      status.Connected,
			QRAvailable:    status.QRAvailable,
		})
	}

	writeJSON(w, accounts)
}

// AccountStatuses returns status values persisted in the database.
// GET /api/accounts/status
func (h *Handlers) AccountStatuses(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	statusByAccountID := h.getAccountStatusMapFromDB()
	statuses := make([]accountRuntimeStatus, 0, len(h.config.WhatsApp))
	for _, account := range h.config.WhatsApp {
		status := accountRuntimeStatus{
			AccountID: account.ID,
			Type:      account.Type,
			Status:    "disconnected",
		}
		if account.Disabled {
			status.Status = "disconnected"
			status.Connected = false
			status.QRAvailable = false
		} else if fromDB, exists := statusByAccountID[account.ID]; exists {
			status = fromDB
		}
		statuses = append(statuses, status)
	}

	writeJSON(w, map[string]interface{}{
		"statuses": statuses,
	})
}

// AddAccount adds a new WhatsApp account to the system
func (h *Handlers) AddAccount(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var account config.WhatsAppConfig
	if err := json.NewDecoder(r.Body).Decode(&account); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Connect to the account
	if err := h.whatsappMgr.Connect(context.Background(), account); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if db := storage.GetDB(); db != nil {
		repo := storage.NewWhatsAppAccountRepository(db)
		if err := repo.UpdateStatus(context.Background(), account.ID, "connecting"); err != nil {
			logging.Warn("Failed to set account status to connecting", "account_id", account.ID, "error", err)
		}
	}

	// Update config
	h.config.WhatsApp = append(h.config.WhatsApp, account)
	if h.configPath != "" {
		if err := config.Save(h.configPath, h.config); err != nil {
			logging.Error("Failed to save config after adding account", "account_id", account.ID, "error", err)
		} else {
			logging.Info("Config saved after adding account", "account_id", account.ID)
		}
	}

	w.WriteHeader(http.StatusCreated)
	writeJSON(w, map[string]string{"status": "ok", "account_id": account.ID})
}

// RemoveAccount removes a WhatsApp account from the system
func (h *Handlers) RemoveAccount(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var req struct {
		ID string `json:"id"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Disconnect the account
	if err := h.whatsappMgr.Disconnect(req.ID); err != nil {
		logging.Warn("Failed to disconnect account during removal", "account_id", req.ID, "error", err)
		// Continue with removal even if disconnect fails
	}

	if db := storage.GetDB(); db != nil {
		repo := storage.NewWhatsAppAccountRepository(db)
		if err := repo.UpdateStatus(context.Background(), req.ID, "disconnected"); err != nil {
			logging.Warn("Failed to set account status to disconnected after removal", "account_id", req.ID, "error", err)
		}
	}

	// Remove from config
	found := false
	newAccounts := make([]config.WhatsAppConfig, 0)
	for _, acc := range h.config.WhatsApp {
		if acc.ID != req.ID {
			newAccounts = append(newAccounts, acc)
		} else {
			found = true
		}
	}

	if !found {
		http.Error(w, "Account not found", http.StatusNotFound)
		return
	}

	h.config.WhatsApp = newAccounts

	// Save config
	if h.configPath != "" {
		if err := config.Save(h.configPath, h.config); err != nil {
			logging.Error("Failed to save config after removing account", "account_id", req.ID, "error", err)
		} else {
			logging.Info("Config saved after removing account", "account_id", req.ID)
		}
	}

	writeJSON(w, map[string]string{"status": "ok"})
}

// DisableAccount disables a WhatsApp account
func (h *Handlers) DisableAccount(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var req struct {
		ID string `json:"id"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Find the account
	found := false
	for i := range h.config.WhatsApp {
		if h.config.WhatsApp[i].ID == req.ID {
			found = true

			// Check if already disabled
			if h.config.WhatsApp[i].Disabled {
				logging.Info("Account already disabled", "account_id", req.ID)
				writeJSON(w, map[string]string{"status": "ok", "message": "account already disabled"})
				return
			}

			// Disconnect the account
			if err := h.whatsappMgr.Disconnect(req.ID); err != nil {
				logging.Warn("Failed to disconnect account during disable", "account_id", req.ID, "error", err)
				// Continue with disabling even if disconnect fails
			}

			// Mark as disabled
			h.config.WhatsApp[i].Disabled = true
			logging.Info("Account disabled", "account_id", req.ID)

			if db := storage.GetDB(); db != nil {
				repo := storage.NewWhatsAppAccountRepository(db)
				if err := repo.UpdateStatus(context.Background(), req.ID, "disconnected"); err != nil {
					logging.Warn("Failed to set account status to disconnected", "account_id", req.ID, "error", err)
				}
			}
			break
		}
	}

	if !found {
		http.Error(w, "Account not found", http.StatusNotFound)
		return
	}

	// Save config
	if h.configPath != "" {
		if err := config.Save(h.configPath, h.config); err != nil {
			logging.Error("Failed to save config after disabling account", "account_id", req.ID, "error", err)
			http.Error(w, "Failed to save configuration", http.StatusInternalServerError)
			return
		}
		logging.Info("Config saved after disabling account", "account_id", req.ID)
	}

	writeJSON(w, map[string]string{"status": "ok", "account_id": req.ID})
}

// EnableAccount enables a WhatsApp account
func (h *Handlers) EnableAccount(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var req struct {
		ID string `json:"id"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Find the account
	var accountConfig *config.WhatsAppConfig
	for i := range h.config.WhatsApp {
		if h.config.WhatsApp[i].ID == req.ID {
			accountConfig = &h.config.WhatsApp[i]
			break
		}
	}

	if accountConfig == nil {
		http.Error(w, "Account not found", http.StatusNotFound)
		return
	}

	// Check if already enabled
	if !accountConfig.Disabled {
		logging.Info("Account already enabled", "account_id", req.ID)
		writeJSON(w, map[string]string{"status": "ok", "message": "account already enabled"})
		return
	}

	// Mark as enabled
	accountConfig.Disabled = false

	// Connect the account
	if err := h.whatsappMgr.Connect(context.Background(), *accountConfig); err != nil {
		logging.Error("Failed to connect account during enable", "account_id", req.ID, "error", err)
		// Revert the disabled flag
		accountConfig.Disabled = true
		http.Error(w, "Failed to connect account: "+err.Error(), http.StatusInternalServerError)
		return
	}

	if db := storage.GetDB(); db != nil {
		repo := storage.NewWhatsAppAccountRepository(db)
		if err := repo.UpdateStatus(context.Background(), req.ID, "connecting"); err != nil {
			logging.Warn("Failed to set account status to connecting", "account_id", req.ID, "error", err)
		}
	}

	logging.Info("Account enabled and connected", "account_id", req.ID)

	// Save config
	if h.configPath != "" {
		if err := config.Save(h.configPath, h.config); err != nil {
			logging.Error("Failed to save config after enabling account", "account_id", req.ID, "error", err)
			http.Error(w, "Failed to save configuration", http.StatusInternalServerError)
			return
		}
		logging.Info("Config saved after enabling account", "account_id", req.ID)
	}

	writeJSON(w, map[string]string{"status": "ok", "account_id": req.ID})
}

// UpdateAccount updates an existing WhatsApp account configuration
func (h *Handlers) UpdateAccount(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost && r.Method != http.MethodPut {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var updates config.WhatsAppConfig
	if err := json.NewDecoder(r.Body).Decode(&updates); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if updates.ID == "" {
		http.Error(w, "Account ID is required", http.StatusBadRequest)
		return
	}

	// Find the account
	found := false
	var oldConfig config.WhatsAppConfig
	for i := range h.config.WhatsApp {
		if h.config.WhatsApp[i].ID == updates.ID {
			found = true
			oldConfig = h.config.WhatsApp[i]

			// Update fields (preserve ID and Type)
			updates.ID = oldConfig.ID
			if updates.Type == "" {
				updates.Type = oldConfig.Type
			}

			h.config.WhatsApp[i] = updates
			logging.Info("Account configuration updated", "account_id", updates.ID)
			break
		}
	}

	if !found {
		http.Error(w, "Account not found", http.StatusNotFound)
		return
	}

	// Sync updated config to database
	if db := storage.GetDB(); db != nil {
		accountRepo := storage.NewWhatsAppAccountRepository(db)
		cfgJSON := ""
		if updates.BusinessAPI != nil {
			if b, err := json.Marshal(updates.BusinessAPI); err == nil {
				cfgJSON = string(b)
			}
		}
		if err := accountRepo.UpdateConfig(context.Background(), updates.ID, updates.PhoneNumber, cfgJSON, !updates.Disabled); err != nil {
			logging.Warn("Failed to sync updated account config to database", "account_id", updates.ID, "error", err)
		}
		if updates.Disabled {
			if err := accountRepo.UpdateStatus(context.Background(), updates.ID, "disconnected"); err != nil {
				logging.Warn("Failed to set account status to disconnected after update", "account_id", updates.ID, "error", err)
			}
		} else if oldConfig.Disabled {
			if err := accountRepo.UpdateStatus(context.Background(), updates.ID, "connecting"); err != nil {
				logging.Warn("Failed to set account status to connecting after update", "account_id", updates.ID, "error", err)
			}
		}
	}

	// If the account was enabled and settings changed, reconnect it
	if !updates.Disabled {
		// Disconnect old connection
		if err := h.whatsappMgr.Disconnect(updates.ID); err != nil {
			logging.Warn("Failed to disconnect account during update", "account_id", updates.ID, "error", err)
		}

		// Reconnect with new settings
		if err := h.whatsappMgr.Connect(context.Background(), updates); err != nil {
			logging.Error("Failed to reconnect account after update", "account_id", updates.ID, "error", err)
			http.Error(w, "Failed to reconnect account: "+err.Error(), http.StatusInternalServerError)
			return
		}
		logging.Info("Account reconnected with new settings", "account_id", updates.ID)
	}

	// Save config
	if h.configPath != "" {
		if err := config.Save(h.configPath, h.config); err != nil {
			logging.Error("Failed to save config after updating account", "account_id", updates.ID, "error", err)
			http.Error(w, "Failed to save configuration", http.StatusInternalServerError)
			return
		}
		logging.Info("Config saved after updating account", "account_id", updates.ID)
	}

	writeJSON(w, map[string]string{"status": "ok", "account_id": updates.ID})
}
