package handler

import (
	"context"
	"encoding/json"
	"errors"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/gofrs/uuid/v5"
	"github.com/saveinmed/backend-go/internal/domain"
	"github.com/saveinmed/backend-go/internal/http/middleware"
)

// --- Request DTOs ---

type createUserRequest struct {
	CompanyID  uuid.UUID `json:"company_id"`
	Role       string    `json:"role"`
	Name       string    `json:"name"`
	Username   string    `json:"username"`
	Email      string    `json:"email"`
	Password   string    `json:"password"`
	Superadmin bool      `json:"superadmin"`
	NomeSocial string    `json:"nome-social"`
	CPF        string    `json:"cpf"`
}

type registerAuthRequest struct {
	CompanyID    *uuid.UUID             `json:"company_id,omitempty"`
	Company      *registerCompanyTarget `json:"company,omitempty"`
	Role         string                 `json:"role"`
	Name         string                 `json:"name"`
	Username     string                 `json:"username"`
	Email        string                 `json:"email"`
	Password     string                 `json:"password"`
	CompanyName  string                 `json:"company_name,omitempty"`  // Frontend sends this
	CNPJ         string                 `json:"cnpj,omitempty"`          // Frontend sends this
}

type registerCompanyTarget struct {
	ID            uuid.UUID `json:"id,omitempty"`
	Category      string    `json:"category"`
	CNPJ          string    `json:"cnpj"`
	CorporateName string    `json:"corporate_name"`
	LicenseNumber string    `json:"license_number"`
	Latitude      float64   `json:"latitude"`
	Longitude     float64   `json:"longitude"`
	City          string    `json:"city"`
	State         string    `json:"state"`
}

type loginRequest struct {
	Username string `json:"username,omitempty"`
	Email    string `json:"email,omitempty"`
	Password string `json:"password"`
}

type forgotPasswordRequest struct {
	Email string `json:"email"`
}

type resetPasswordRequest struct {
	Token    string `json:"token"`
	Password string `json:"password"`
}

type verifyEmailRequest struct {
	Token string `json:"token"`
}

type authResponse struct {
	Token     string    `json:"access_token"`
	ExpiresAt time.Time `json:"expires_at"`
}

type messageResponse struct {
	Message string `json:"message"`
}

type resetTokenResponse struct {
	Message    string     `json:"message"`
	ResetToken string     `json:"reset_token,omitempty"`
	ExpiresAt  *time.Time `json:"expires_at,omitempty"`
}

type inventoryAdjustRequest struct {
	ProductID uuid.UUID `json:"product_id"`
	Delta     int64     `json:"delta"`
	Reason    string    `json:"reason"`
}

type addCartItemRequest struct {
	ProductID uuid.UUID `json:"product_id"`
	Quantity  int64     `json:"quantity"`
}

type createReviewRequest struct {
	OrderID uuid.UUID `json:"order_id"`
	Rating  int       `json:"rating"`
	Comment string    `json:"comment"`
}

type updateUserRequest struct {
	CompanyID     *uuid.UUID `json:"company_id,omitempty"`
	Role          *string    `json:"role,omitempty"`
	Name          *string    `json:"name,omitempty"`
	Username      *string    `json:"username,omitempty"`
	Email         *string    `json:"email,omitempty"`
	Password      *string    `json:"password,omitempty"`
	EmpresasDados []string   `json:"empresasDados"` // Frontend sends array of strings
	Enderecos     []string   `json:"enderecos"`     // Frontend sends array of strings

	// Ignored fields sent by frontend to prevent "unknown field" errors
	ID               interface{} `json:"id,omitempty"`
	EmailVerified    interface{} `json:"email_verified,omitempty"`
	CreatedAt        interface{} `json:"created_at,omitempty"`
	UpdatedAt        interface{} `json:"updated_at,omitempty"`
	Nome             interface{} `json:"nome,omitempty"`
	Ativo            interface{} `json:"ativo,omitempty"`
	CPF              interface{} `json:"cpf,omitempty"`
	NomeSocial       interface{} `json:"nome_social,omitempty"`
	RegistroCompleto interface{} `json:"registro_completo,omitempty"`
	Nivel            interface{} `json:"nivel,omitempty"`
	CompanyName      interface{} `json:"company_name,omitempty"`
	Superadmin       interface{} `json:"superadmin,omitempty"`
}

type requester struct {
	ID        uuid.UUID
	Role      string
	CompanyID *uuid.UUID
}

type registerCompanyRequest struct {
	Category      string  `json:"category"`
	CNPJ          string  `json:"cnpj"`
	CorporateName string  `json:"corporate_name"`
	LicenseNumber string  `json:"license_number"`
	Latitude      float64 `json:"latitude"`
	Longitude     float64 `json:"longitude"`
	City          string  `json:"city"`
	State         string  `json:"state"`

	// Portuguese Frontend Compatibility
	RazaoSocial              string  `json:"razao-social"`
	NomeFantasia             string  `json:"nome-fantasia"`
	DataAbertura             string  `json:"data-abertura"` // Fixed: frontend sends hyphen
	Telefone                 string  `json:"telefone"`
	CodigoAtividade          string  `json:"codigo_atividade"`
	DescricaoAtividade       string  `json:"descricao_atividade"`
	Situacao                 string  `json:"situacao"`                   // Ignored for now
	NaturezaJuridica         string  `json:"natureza-juridica"`          // Ignored for now
	Porte                    string  `json:"porte"`                      // Ignored for now
	AtividadePrincipal       string  `json:"atividade-principal"`        // Frontend might send this
	AtividadePrincipalCodigo string  `json:"atividade-principal-codigo"` // Frontend sends this
	AtividadePrincipalDesc   string  `json:"atividade-principal-desc"`   // Frontend sends this
	Email                    string  `json:"email"`                      // Frontend sends this
	CapitalSocial            float64 `json:"capital-social"`             // Frontend sends this (number)
	AddressID                string  `json:"enderecoID"`                 // Frontend sends this
	TipoFrete                string  `json:"tipoFrete"`                  // Frontend sends this
	RaioEntregaKm            float64 `json:"raioEntregaKm"`              // Frontend sends this
	TaxaEntrega              float64 `json:"taxaEntrega"`                // Frontend sends this
	ValorFreteKm             float64 `json:"valorFreteKm"`               // Frontend sends this
}

type updateCompanyRequest struct {
	Category      *string  `json:"category,omitempty"`
	CNPJ          *string  `json:"cnpj,omitempty"`
	CorporateName *string  `json:"corporate_name,omitempty"`
	LicenseNumber *string  `json:"license_number,omitempty"`
	IsVerified    *bool    `json:"is_verified,omitempty"`
	Latitude      *float64 `json:"latitude,omitempty"`
	Longitude     *float64 `json:"longitude,omitempty"`
	City          *string  `json:"city,omitempty"`
	State         *string  `json:"state,omitempty"`

	// Portuguese Frontend Compatibility (Partial Updates)
	RazaoSocial              *string  `json:"razao-social,omitempty"`
	NomeFantasia             *string  `json:"nome-fantasia,omitempty"`
	DataAbertura             *string  `json:"data-abertura,omitempty"`
	Telefone                 *string  `json:"telefone,omitempty"`
	CodigoAtividade          *string  `json:"codigo_atividade,omitempty"`
	DescricaoAtividade       *string  `json:"descricao_atividade,omitempty"`
	Situacao                 *string  `json:"situacao,omitempty"`
	NaturezaJuridica         *string  `json:"natureza-juridica,omitempty"`
	Porte                    *string  `json:"porte,omitempty"`
	AtividadePrincipal       *string  `json:"atividade-principal,omitempty"`
	AtividadePrincipalCodigo *string  `json:"atividade-principal-codigo,omitempty"`
	AtividadePrincipalDesc   *string  `json:"atividade-principal-desc,omitempty"`
	Email                    *string  `json:"email,omitempty"`
	CapitalSocial            *float64 `json:"capital-social,omitempty"`
	AddressID                *string  `json:"enderecoID,omitempty"`
	TipoFrete                *string  `json:"tipoFrete,omitempty"`
	RaioEntregaKm            *float64 `json:"raioEntregaKm,omitempty"`
	TaxaEntrega              *float64 `json:"taxaEntrega,omitempty"`
	ValorFreteKm             *float64 `json:"valorFreteKm,omitempty"`
}

type registerProductRequest struct {
	SellerID       uuid.UUID `json:"seller_id"`
	EANCode        string    `json:"ean_code"`
	Name           string    `json:"name"`
	Description    string    `json:"description"`
	Manufacturer   string    `json:"manufacturer"`
	Category       string    `json:"category"`
	Subcategory    string    `json:"subcategory"`
	Batch          string    `json:"batch,omitempty"`      // Compatibility
	ExpiresAt      string    `json:"expires_at,omitempty"` // Compatibility
	Stock          int64     `json:"stock,omitempty"`      // Compatibility
	PriceCents     int64     `json:"price_cents"`
	SalePriceCents int64     `json:"sale_price_cents,omitempty"` // New field for frontend compatibility
	// New Fields
	InternalCode            string `json:"internal_code"`
	FactoryPriceCents       int64  `json:"factory_price_cents"`
	PMCCents                int64  `json:"pmc_cents"`
	CommercialDiscountCents int64  `json:"commercial_discount_cents"`
	TaxSubstitutionCents    int64  `json:"tax_substitution_cents"`
	InvoicePriceCents       int64  `json:"invoice_price_cents"`
}

type updateProductRequest struct {
	SellerID       *uuid.UUID `json:"seller_id,omitempty"`
	EANCode        *string    `json:"ean_code,omitempty"`
	Name           *string    `json:"name,omitempty"`
	Description    *string    `json:"description,omitempty"`
	Manufacturer   *string    `json:"manufacturer,omitempty"`
	Category       *string    `json:"category,omitempty"`
	Subcategory    *string    `json:"subcategory,omitempty"`
	PriceCents     *int64     `json:"price_cents,omitempty"`
	SalePriceCents *int64     `json:"sale_price_cents,omitempty"` // Compatibility
	// New Fields
	InternalCode            *string  `json:"internal_code,omitempty"`
	FactoryPriceCents       *int64   `json:"factory_price_cents,omitempty"`
	PMCCents                *int64   `json:"pmc_cents,omitempty"`
	CommercialDiscountCents *int64   `json:"commercial_discount_cents,omitempty"`
	TaxSubstitutionCents    *int64   `json:"tax_substitution_cents,omitempty"`
	InvoicePriceCents       *int64   `json:"invoice_price_cents,omitempty"`
	Stock                   *int64   `json:"qtdade_estoque,omitempty"` // Frontend compatibility
	PrecoVenda              *float64 `json:"preco_venda,omitempty"`    // Frontend compatibility (float)
}

type createOrderRequest struct {
	BuyerID       uuid.UUID              `json:"buyer_id"`
	SellerID      uuid.UUID              `json:"seller_id"`
	Items         []domain.OrderItem     `json:"items"`
	Shipping      domain.ShippingAddress `json:"shipping"`
	PaymentMethod orderPaymentMethod     `json:"payment_method"`
}

// orderPaymentMethod handles both frontend formats:
// - Plain string: "pix" | "credit_card" | "debit_card"
// - Object:       { "type": "pix", "installments": 1 }
type orderPaymentMethod struct {
	Type         string `json:"type"`
	Installments int    `json:"installments"`
}

func (m *orderPaymentMethod) UnmarshalJSON(data []byte) error {
	// Try plain string first
	var s string
	if err := json.Unmarshal(data, &s); err == nil {
		m.Type = s
		m.Installments = 1
		return nil
	}
	// Fall back to object format
	type alias orderPaymentMethod
	var obj alias
	if err := json.Unmarshal(data, &obj); err != nil {
		return err
	}
	*m = orderPaymentMethod(obj)
	return nil
}

type createShipmentRequest struct {
	OrderID          uuid.UUID `json:"order_id"`
	Carrier          string    `json:"carrier"`
	TrackingCode     string    `json:"tracking_code"`
	ExternalTracking string    `json:"external_tracking"`
}

type updateStatusRequest struct {
	Status string `json:"status"`
}

type shippingSettingsRequest struct {
	Active                     bool    `json:"active"`
	MaxRadiusKm                float64 `json:"max_radius_km"`
	PricePerKmCents            int64   `json:"price_per_km_cents"`
	MinFeeCents                int64   `json:"min_fee_cents"`
	FreeShippingThresholdCents *int64  `json:"free_shipping_threshold_cents,omitempty"`
	PickupActive               bool    `json:"pickup_active"`
	PickupAddress              string  `json:"pickup_address,omitempty"`
	PickupHours                string  `json:"pickup_hours,omitempty"`
	Latitude                   float64 `json:"latitude"` // Store location for radius calc
	Longitude                  float64 `json:"longitude"`
}

type shippingCalculateRequest struct {
	VendorID       uuid.UUID  `json:"vendor_id"`
	CartTotalCents int64      `json:"cart_total_cents"`
	BuyerLatitude  *float64   `json:"buyer_latitude,omitempty"`
	BuyerLongitude *float64   `json:"buyer_longitude,omitempty"`
	AddressID      *uuid.UUID `json:"address_id,omitempty"`
	PostalCode     string     `json:"postal_code,omitempty"`
}

type createAddressRequest struct {
	EntityID   *uuid.UUID `json:"entity_id,omitempty"` // Allow admin to specify owner
	Title      string     `json:"titulo"`
	ZipCode    string     `json:"cep"`
	Street     string     `json:"logradouro"`
	Number     string     `json:"numero"`
	Complement string     `json:"complemento"`
	District   string     `json:"bairro"`
	City       string     `json:"cidade"`
	State      string     `json:"estado"` // JSON from frontend sends "estado"
	Country    string     `json:"pais"`   // JSON includes "pais"
}

// --- Utility Functions ---

func writeJSON(w http.ResponseWriter, status int, v any) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	_ = json.NewEncoder(w).Encode(v)
}

func writeError(w http.ResponseWriter, status int, err error) {
	writeJSON(w, status, map[string]string{"error": err.Error()})
}

func decodeJSON(ctx context.Context, r *http.Request, v any) error {
	ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
	defer cancel()

	// Using standard encoding/json for maximum compatibility and permissive decoding
	if err := json.NewDecoder(r.Body).Decode(v); err != nil {
		return err
	}
	return ctx.Err()
}

func parseUUIDFromPath(path string) (uuid.UUID, error) {
	parts := splitPath(path)
	for i := len(parts) - 1; i >= 0; i-- {
		if id, err := uuid.FromString(parts[i]); err == nil {
			return id, nil
		}
	}
	return uuid.UUID{}, errors.New("missing resource id")
}

func splitPath(p string) []string {
	var parts []string
	start := 0
	for i := 0; i < len(p); i++ {
		if p[i] == '/' {
			if i > start {
				parts = append(parts, p[start:i])
			}
			start = i + 1
		}
	}
	if start < len(p) {
		parts = append(parts, p[start:])
	}
	return parts
}

func isValidStatus(status string) bool {
	switch domain.OrderStatus(status) {
	case domain.OrderStatusPending, domain.OrderStatusPaid, domain.OrderStatusInvoiced, domain.OrderStatusDelivered:
		return true
	default:
		return false
	}
}

func parsePagination(r *http.Request) (int, int) {
	page := 1
	pageSize := 20

	if v := r.URL.Query().Get("page"); v != "" {
		if p, err := strconv.Atoi(v); err == nil && p > 0 {
			page = p
		}
	}

	if v := r.URL.Query().Get("page_size"); v != "" {
		if ps, err := strconv.Atoi(v); err == nil && ps > 0 {
			pageSize = ps
		}
	}

	return page, pageSize
}

func getRequester(r *http.Request) (requester, error) {
	if claims, ok := middleware.GetClaims(r.Context()); ok {
		return requester{ID: claims.UserID, Role: claims.Role, CompanyID: claims.CompanyID}, nil
	}
	role := r.Header.Get("X-User-Role")
	if role == "" {
		role = "Admin"
	}

	var companyID *uuid.UUID
	if cid := r.Header.Get("X-Company-ID"); cid != "" {
		id, err := uuid.FromString(cid)
		if err != nil {
			return requester{}, errors.New("invalid X-Company-ID header")
		}
		companyID = &id
	}

	return requester{Role: role, CompanyID: companyID}, nil
}

func parseBearerToken(r *http.Request) (string, error) {
	authHeader := r.Header.Get("Authorization")
	if authHeader == "" {
		return "", errors.New("missing Authorization header")
	}
	parts := strings.SplitN(authHeader, " ", 2)
	if len(parts) != 2 || !strings.EqualFold(parts[0], "bearer") {
		return "", errors.New("invalid Authorization header")
	}
	token := strings.TrimSpace(parts[1])
	if token == "" {
		return "", errors.New("token is required")
	}
	return token, nil
}
