package admin

import (
	"crussell/db"
	"encoding/json"
	"fmt"
	"log"
	"log/slog"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

type BusinessSettings struct {
	BusinessName          string  `json:"business_name"`
	BusinessAddress       string  `json:"business_address"`
	BusinessPhone         *string `json:"business_phone,omitempty"`
	BusinessEmail         *string `json:"business_email,omitempty"`
	VATRegistrationNumber *string `json:"vat_registration_number,omitempty"`
	IsVATRegistered       bool    `json:"is_vat_registered"`
	DefaultVATRate        float64 `json:"default_vat_rate"`
	CurrencyCode          string  `json:"currency_code"`
	WebsiteURL            *string `json:"website_url,omitempty"`
	GiftCardExpiryMonths  int     `json:"gift_card_expiry_months"`
	VoucherType           string  `json:"voucher_type"`
}

func validateURL(rawURL string) error {
	parsed, err := url.Parse(rawURL)
	if err != nil {
		return err
	}
	if parsed.Scheme != "http" && parsed.Scheme != "https" {
		return fmt.Errorf("must start with http:// or https://")
	}
	if parsed.Host == "" {
		return fmt.Errorf("host is required")
	}
	return nil
}

// PublicBusinessInfo contains the non-sensitive subset of business settings
// that is safe to expose to unauthenticated or non-admin users.
type PublicBusinessInfo struct {
	BusinessName          string  `json:"business_name"`
	BusinessAddress       string  `json:"business_address"`
	BusinessPhone         *string `json:"business_phone,omitempty"`
	BusinessEmail         *string `json:"business_email,omitempty"`
	IsVATRegistered       bool    `json:"is_vat_registered"`
	VATRegistrationNumber *string `json:"vat_registration_number,omitempty"`
	DefaultVATRate        float64 `json:"default_vat_rate"`
}

func GetPublicBusinessInfo(w http.ResponseWriter, r *http.Request) {
	var info PublicBusinessInfo
	err := db.Conn.QueryRow(r.Context(), `
		SELECT business_name, business_address, business_phone, business_email,
		       is_vat_registered, vat_registration_number, default_vat_rate
		FROM business_settings
		LIMIT 1
	`).Scan(
		&info.BusinessName, &info.BusinessAddress, &info.BusinessPhone, &info.BusinessEmail,
		&info.IsVATRegistered, &info.VATRegistrationNumber, &info.DefaultVATRate,
	)
	if err != nil {
		log.Printf("Failed to fetch public business info: %v", err)
		http.Error(w, "Failed to fetch business info", http.StatusInternalServerError)
		return
	}

	_ = json.NewEncoder(w).Encode(info)
}

func GetBusinessSettings(w http.ResponseWriter, r *http.Request) {
	var s BusinessSettings
	err := db.Conn.QueryRow(r.Context(), `
		SELECT business_name, business_address, business_phone, business_email,
		       vat_registration_number, is_vat_registered, default_vat_rate,
		       currency_code, website_url, gift_card_expiry_months, voucher_type
		FROM business_settings
		LIMIT 1
	`).Scan(
		&s.BusinessName, &s.BusinessAddress, &s.BusinessPhone, &s.BusinessEmail,
		&s.VATRegistrationNumber, &s.IsVATRegistered, &s.DefaultVATRate,
		&s.CurrencyCode, &s.WebsiteURL, &s.GiftCardExpiryMonths, &s.VoucherType,
	)
	if err != nil {
		log.Printf("Failed to fetch business settings: %v", err)
		http.Error(w, "Failed to fetch settings", http.StatusInternalServerError)
		return
	}

	_ = json.NewEncoder(w).Encode(s)
}

type UpdateBusinessSettingsRequest struct {
	BusinessName          *string  `json:"business_name,omitempty"`
	BusinessAddress       *string  `json:"business_address,omitempty"`
	BusinessPhone         *string  `json:"business_phone,omitempty"`
	BusinessEmail         *string  `json:"business_email,omitempty"`
	VATRegistrationNumber *string  `json:"vat_registration_number,omitempty"`
	IsVATRegistered       *bool    `json:"is_vat_registered,omitempty"`
	DefaultVATRate        *float64 `json:"default_vat_rate,omitempty"`
	WebsiteURL            *string  `json:"website_url,omitempty"`
	GiftCardExpiryMonths  *int     `json:"gift_card_expiry_months,omitempty"`
	VoucherType           *string  `json:"voucher_type,omitempty"`
}

func UpdateBusinessSettings(w http.ResponseWriter, r *http.Request) {
	var req UpdateBusinessSettingsRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	if req.BusinessName != nil && (len(*req.BusinessName) == 0 || len(*req.BusinessName) > 255) {
		http.Error(w, "business_name must be between 1 and 255 characters", http.StatusBadRequest)
		return
	}
	if req.BusinessAddress != nil && len(*req.BusinessAddress) == 0 {
		http.Error(w, "business_address must not be empty", http.StatusBadRequest)
		return
	}
	if req.BusinessPhone != nil && len(*req.BusinessPhone) > 20 {
		http.Error(w, "business_phone must be 20 characters or fewer", http.StatusBadRequest)
		return
	}
	if req.BusinessEmail != nil && len(*req.BusinessEmail) > 254 {
		http.Error(w, "business_email must be 254 characters or fewer", http.StatusBadRequest)
		return
	}
	if req.VATRegistrationNumber != nil && *req.VATRegistrationNumber != "" {
		v := *req.VATRegistrationNumber
		if len(v) < 11 || len(v) > 14 {
			http.Error(w, "vat_registration_number must be 11 characters (GB + 9 digits) or 14 characters (GB + 12 digits)", http.StatusBadRequest)
			return
		}
		if v[:2] != "GB" {
			http.Error(w, "vat_registration_number must start with 'GB'", http.StatusBadRequest)
			return
		}
		digits := v[2:]
		if len(digits) != 9 && len(digits) != 12 {
			http.Error(w, "vat_registration_number must have 9 or 12 digits after 'GB'", http.StatusBadRequest)
			return
		}
		for _, c := range digits {
			if c < '0' || c > '9' {
				http.Error(w, "vat_registration_number must contain only digits after 'GB'", http.StatusBadRequest)
				return
			}
		}
	}
	if req.WebsiteURL != nil && *req.WebsiteURL != "" {
		if err := validateURL(*req.WebsiteURL); err != nil {
			http.Error(w, "website_url: "+err.Error(), http.StatusBadRequest)
			return
		}
	}
	if req.VoucherType != nil && *req.VoucherType != "SPV" && *req.VoucherType != "MPV" {
		http.Error(w, "voucher_type must be 'SPV' or 'MPV'", http.StatusBadRequest)
		return
	}
	if req.GiftCardExpiryMonths != nil && *req.GiftCardExpiryMonths < 1 {
		http.Error(w, "gift_card_expiry_months must be at least 1", http.StatusBadRequest)
		return
	}
	if req.DefaultVATRate != nil && (*req.DefaultVATRate < 0 || *req.DefaultVATRate > 100) {
		http.Error(w, "default_vat_rate must be between 0 and 100", http.StatusBadRequest)
		return
	}

	setClauses := []string{}
	args := []any{}
	argIdx := 1

	if req.BusinessName != nil {
		setClauses = append(setClauses, "business_name = $"+strconv.Itoa(argIdx))
		args = append(args, *req.BusinessName)
		argIdx++
	}
	if req.BusinessAddress != nil {
		setClauses = append(setClauses, "business_address = $"+strconv.Itoa(argIdx))
		args = append(args, *req.BusinessAddress)
		argIdx++
	}
	if req.BusinessPhone != nil {
		setClauses = append(setClauses, "business_phone = $"+strconv.Itoa(argIdx))
		args = append(args, *req.BusinessPhone)
		argIdx++
	}
	if req.BusinessEmail != nil {
		setClauses = append(setClauses, "business_email = $"+strconv.Itoa(argIdx))
		args = append(args, *req.BusinessEmail)
		argIdx++
	}
	if req.VATRegistrationNumber != nil {
		setClauses = append(setClauses, "vat_registration_number = $"+strconv.Itoa(argIdx))
		args = append(args, *req.VATRegistrationNumber)
		argIdx++
	}
	if req.IsVATRegistered != nil {
		setClauses = append(setClauses, "is_vat_registered = $"+strconv.Itoa(argIdx))
		args = append(args, *req.IsVATRegistered)
		argIdx++
	}
	if req.DefaultVATRate != nil {
		setClauses = append(setClauses, "default_vat_rate = $"+strconv.Itoa(argIdx))
		args = append(args, *req.DefaultVATRate)
		argIdx++
	}
	if req.WebsiteURL != nil {
		setClauses = append(setClauses, "website_url = $"+strconv.Itoa(argIdx))
		args = append(args, *req.WebsiteURL)
		argIdx++
	}
	if req.GiftCardExpiryMonths != nil {
		setClauses = append(setClauses, "gift_card_expiry_months = $"+strconv.Itoa(argIdx))
		args = append(args, *req.GiftCardExpiryMonths)
		argIdx++
	}
	if req.VoucherType != nil {
		setClauses = append(setClauses, "voucher_type = $"+strconv.Itoa(argIdx))
		args = append(args, *req.VoucherType)
	}

	if len(setClauses) == 0 {
		http.Error(w, "No fields to update", http.StatusBadRequest)
		return
	}

	var query strings.Builder
	query.WriteString("UPDATE business_settings SET ")
	for i, clause := range setClauses {
		if i > 0 {
			query.WriteString(", ")
		}
		query.WriteString(clause)
	}

	tx, err := db.Conn.Begin(r.Context())
	if err != nil {
		log.Printf("Failed to begin transaction: %v", err)
		http.Error(w, "Failed to update settings", http.StatusInternalServerError)
		return
	}
	defer func() {
    if err := tx.Rollback(r.Context()); err != nil {
        slog.Error("failed to rollback transaction", "err", err)
    }
}()

	_, err = tx.Exec(r.Context(), query.String(), args...)
	if err != nil {
		log.Printf("Failed to update business settings: %v", err)
		http.Error(w, "Failed to update settings", http.StatusInternalServerError)
		return
	}

	if req.IsVATRegistered != nil && *req.IsVATRegistered {
		vatRate := 20.0
		if req.DefaultVATRate != nil {
			vatRate = *req.DefaultVATRate
		}
		var payUpdated, tillUpdated int
		var totalVAT, totalNet float64
		// Use '2000-01-01' to cover all historical payments. Under UK VAT law,
		// the effective registration date may be backdated — this ensures all
		// past completed payments and till sales get VAT applied retroactively.
		vatErr := tx.QueryRow(r.Context(),
			"SELECT payments_updated, till_sales_updated, total_vat_calculated, total_net_calculated FROM enable_vat_registration('2000-01-01'::date, $1, $2)",
			vatRate, req.VATRegistrationNumber,
		).Scan(&payUpdated, &tillUpdated, &totalVAT, &totalNet)
		if vatErr != nil {
			log.Printf("Failed to enable VAT retroactively: %v", vatErr)
			http.Error(w, "Business settings saved but failed to retroactively apply VAT to past payments. The database function enable_vat_registration returned an error. Please try again or contact support.", http.StatusInternalServerError)
			return
		}
		log.Printf("VAT enabled retroactively: %d payments (+£%.2f VAT), %d till sales updated",
			payUpdated, totalVAT, tillUpdated)
	}

	if err := tx.Commit(r.Context()); err != nil {
		log.Printf("Failed to commit settings update: %v", err)
		http.Error(w, "Failed to save settings", http.StatusInternalServerError)
		return
	}

	GetBusinessSettings(w, r)
}
