package api

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

	"archivmail/internal/auth"
	pop3store "archivmail/internal/pop3"
	"archivmail/internal/userstore"
)

// ── POP3 handlers ──────────────────────────────────────────────────────────

func (s *Server) handleListPop3(w http.ResponseWriter, r *http.Request) {
	if s.pop3Store == nil {
		writeError(w, http.StatusServiceUnavailable, "POP3 not configured")
		return
	}
	sess := sessionFromCtx(r.Context())
	// SEC-03: Use HasRole to correctly check admin privileges (domain_admin, admin, superadmin).
	isAdmin := auth.HasRole(sess.Role, userstore.RoleDomainAdmin)
	accounts, err := s.pop3Store.List(r.Context(), sess.Username, isAdmin, sess.TenantID)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "failed to list POP3 accounts")
		return
	}
	if accounts == nil {
		accounts = []pop3store.Account{}
	}
	writeJSON(w, http.StatusOK, accounts)
}

func (s *Server) handleCreatePop3(w http.ResponseWriter, r *http.Request) {
	if s.pop3Store == nil {
		writeError(w, http.StatusServiceUnavailable, "POP3 not configured")
		return
	}
	var req struct {
		Name          string `json:"name"`
		Host          string `json:"host"`
		Port          int    `json:"port"`
		TLS           string `json:"tls"`
		TLSSkipVerify bool   `json:"tls_skip_verify"`
		Username      string `json:"username"`
		Password      string `json:"password"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}
	if req.Name == "" || req.Host == "" || req.Username == "" || req.Password == "" {
		writeError(w, http.StatusBadRequest, "name, host, username and password are required")
		return
	}
	if req.Port <= 0 {
		req.Port = 110
	}
	if req.TLS == "" {
		req.TLS = "none"
	}

	sess := sessionFromCtx(r.Context())
	acc := pop3store.Account{
		Owner:         sess.Username,
		Name:          req.Name,
		Host:          req.Host,
		Port:          req.Port,
		TLS:           req.TLS,
		TLSSkipVerify: req.TLSSkipVerify,
		Username:      req.Username,
		TenantID:      sess.TenantID,
	}

	created, err := s.pop3Store.Create(r.Context(), acc, req.Password)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "failed to create POP3 account")
		return
	}

	writeJSON(w, http.StatusCreated, created)
}

func (s *Server) handleDeletePop3(w http.ResponseWriter, r *http.Request) {
	if s.pop3Store == nil {
		writeError(w, http.StatusServiceUnavailable, "POP3 not configured")
		return
	}
	idStr := r.PathValue("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid id")
		return
	}

	acc, err := s.pop3Store.Get(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, "account not found")
		return
	}

	sess := sessionFromCtx(r.Context())
	if acc.Owner != sess.Username && !auth.HasRole(sess.Role, userstore.RoleDomainAdmin) {
		writeError(w, http.StatusForbidden, "access denied")
		return
	}
	if !tenantAccessAllowed(sess, acc.TenantID) {
		writeError(w, http.StatusForbidden, "access denied")
		return
	}

	if err := s.pop3Store.Delete(r.Context(), id); err != nil {
		writeError(w, http.StatusInternalServerError, "failed to delete account")
		return
	}

	writeJSON(w, http.StatusOK, map[string]bool{"ok": true})
}

func (s *Server) handleTestPop3(w http.ResponseWriter, r *http.Request) {
	var req struct {
		Host          string `json:"host"`
		Port          int    `json:"port"`
		TLS           string `json:"tls"`
		TLSSkipVerify bool   `json:"tls_skip_verify"`
		Username      string `json:"username"`
		Password      string `json:"password"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}
	if req.Host == "" || req.Username == "" || req.Password == "" {
		writeError(w, http.StatusBadRequest, "host, username and password are required")
		return
	}
	if req.Port <= 0 {
		req.Port = 110
	}
	if req.TLS == "" {
		req.TLS = "none"
	}

	c, err := pop3store.Dial(req.Host, req.Port, req.TLS, req.TLSSkipVerify)
	if err != nil {
		writeJSON(w, http.StatusOK, map[string]interface{}{
			"ok":      false,
			"message": fmt.Sprintf("Verbindung fehlgeschlagen: %v", err),
		})
		return
	}
	defer c.Close()

	if err := c.Login(req.Username, req.Password); err != nil {
		writeJSON(w, http.StatusOK, map[string]interface{}{
			"ok":      false,
			"message": fmt.Sprintf("Anmeldung fehlgeschlagen: %v", err),
		})
		return
	}

	count, totalSize, err := c.Stat()
	if err != nil {
		writeJSON(w, http.StatusOK, map[string]interface{}{
			"ok":      false,
			"message": fmt.Sprintf("STAT fehlgeschlagen: %v", err),
		})
		return
	}

	_ = c.Quit()
	writeJSON(w, http.StatusOK, map[string]interface{}{
		"ok":               true,
		"message":          fmt.Sprintf("Verbindung erfolgreich: %d E-Mails", count),
		"message_count":    count,
		"total_size_bytes": totalSize,
	})
}

func (s *Server) handleStartPop3Import(w http.ResponseWriter, r *http.Request) {
	if s.pop3Store == nil || s.pop3Importer == nil {
		writeError(w, http.StatusServiceUnavailable, "POP3 not configured")
		return
	}
	idStr := r.PathValue("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid id")
		return
	}

	acc, err := s.pop3Store.Get(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, "account not found")
		return
	}

	sess := sessionFromCtx(r.Context())
	if acc.Owner != sess.Username && !auth.HasRole(sess.Role, userstore.RoleDomainAdmin) {
		writeError(w, http.StatusForbidden, "access denied")
		return
	}
	if !tenantAccessAllowed(sess, acc.TenantID) {
		writeError(w, http.StatusForbidden, "access denied")
		return
	}

	if acc.Status == "running" {
		writeError(w, http.StatusConflict, "import already running")
		return
	}

	go s.pop3Importer.Run(context.Background(), id)

	// Return current account state (status will switch to "running" shortly)
	acc.Status = "running"
	writeJSON(w, http.StatusOK, acc)
}

func (s *Server) handlePop3Progress(w http.ResponseWriter, r *http.Request) {
	if s.pop3Store == nil {
		writeError(w, http.StatusServiceUnavailable, "POP3 not configured")
		return
	}
	idStr := r.PathValue("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid id")
		return
	}

	acc, err := s.pop3Store.Get(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, "account not found")
		return
	}

	sess := sessionFromCtx(r.Context())
	if acc.Owner != sess.Username && !auth.HasRole(sess.Role, userstore.RoleDomainAdmin) {
		writeError(w, http.StatusForbidden, "access denied")
		return
	}
	if !tenantAccessAllowed(sess, acc.TenantID) {
		writeError(w, http.StatusForbidden, "access denied")
		return
	}

	writeJSON(w, http.StatusOK, acc)
}
