// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later

package licensing

import (
	"net/http"
	"time"

	licensing_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/licensing"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/context"
)

// validateResponse is the public validation result.
type validateResponse struct {
	Valid      bool   `json:"valid"`
	Tier       string `json:"tier,omitempty"`
	TierName   string `json:"tier_name,omitempty"`
	Status     string `json:"status,omitempty"`
	Reason     string `json:"reason,omitempty"`
	DomainsUsed int   `json:"domains_used,omitempty"`
	DomainsMax  int   `json:"domains_max,omitempty"`
	ExpiresAt  string `json:"expires_at,omitempty"`
}

// statusResponse is the full license detail for authenticated callers.
type statusResponse struct {
	Valid        bool     `json:"valid"`
	DLID         string   `json:"dlid"`
	Tier         string   `json:"tier"`
	TierName     string   `json:"tier_name"`
	Status       string   `json:"status"`
	Products     []string `json:"products"`
	DomainsUsed  int      `json:"domains_used"`
	DomainsMax   int      `json:"domains_max"`
	ExpiresAt    string   `json:"expires_at,omitempty"`
	CreatedAt    string   `json:"created_at"`
}

// Validate handles GET /api/v1/licensing/validate?dlid=XXX&product=YYY&domain=ZZZ
// Public endpoint — no auth required. Returns minimal valid/invalid with reason.
func Validate(ctx *context.APIContext) {
	dlid := ctx.FormString("dlid")
	product := ctx.FormString("product")
	domain := ctx.FormString("domain")

	if dlid == "" {
		ctx.JSON(http.StatusOK, validateResponse{Valid: false, Reason: "missing_dlid"})
		return
	}

	if !licensing_model.ValidateDLIDFormat(dlid) {
		ctx.JSON(http.StatusOK, validateResponse{Valid: false, Reason: "invalid_dlid"})
		return
	}

	license, err := licensing_model.GetLicenseByDLID(ctx, dlid)
	if err != nil {
		log.Error("Validate: GetLicenseByDLID: %v", err)
		ctx.JSON(http.StatusOK, validateResponse{Valid: false, Reason: "internal_error"})
		return
	}
	if license == nil {
		ctx.JSON(http.StatusOK, validateResponse{Valid: false, Reason: "invalid_dlid"})
		return
	}

	if license.Status == "revoked" {
		ctx.JSON(http.StatusOK, validateResponse{Valid: false, Reason: "revoked"})
		return
	}
	if license.Status == "suspended" {
		ctx.JSON(http.StatusOK, validateResponse{Valid: false, Reason: "suspended"})
		return
	}
	if license.IsExpired() {
		ctx.JSON(http.StatusOK, validateResponse{Valid: false, Reason: "expired"})
		return
	}

	// Check product entitlement if product is specified
	if product != "" {
		has, err := licensing_model.HasEntitlement(ctx, license.ID, product)
		if err != nil {
			log.Error("Validate: HasEntitlement: %v", err)
		}
		if !has {
			ctx.JSON(http.StatusOK, validateResponse{Valid: false, Reason: "no_entitlement"})
			return
		}
	}

	// Check domain limit if domain is specified
	if domain != "" {
		domainCount, _ := licensing_model.CountActivations(ctx, license.ID)
		if license.MaxDomains > 0 && domainCount >= int64(license.MaxDomains) {
			// Check if this domain is already activated
			acts, _ := licensing_model.GetActivationsByLicense(ctx, license.ID)
			found := false
			for _, a := range acts {
				if a.Domain == domain {
					found = true
					break
				}
			}
			if !found {
				ctx.JSON(http.StatusOK, validateResponse{Valid: false, Reason: "domain_limit"})
				return
			}
		}
	}

	// Look up tier name
	tierName := license.Tier
	tier, _ := licensing_model.GetProductTierByKey(ctx, license.Tier)
	if tier != nil {
		tierName = tier.TierName
	}

	domainCount, _ := licensing_model.CountActivations(ctx, license.ID)

	resp := validateResponse{
		Valid:       true,
		Tier:        license.Tier,
		TierName:    tierName,
		Status:      license.Status,
		DomainsUsed: int(domainCount),
		DomainsMax:  license.MaxDomains,
	}
	if license.ExpiresAt > 0 {
		resp.ExpiresAt = time.Unix(int64(license.ExpiresAt), 0).UTC().Format(time.RFC3339)
	}

	ctx.JSON(http.StatusOK, resp)
}

// Status handles GET /api/v1/licensing/{dlid}/status
// Authenticated endpoint — returns full license detail with entitlement list.
func Status(ctx *context.APIContext) {
	dlid := ctx.PathParam("dlid")

	if dlid == "" || !licensing_model.ValidateDLIDFormat(dlid) {
		ctx.JSON(http.StatusBadRequest, map[string]string{"error": "invalid DLID format"})
		return
	}

	license, err := licensing_model.GetLicenseByDLID(ctx, dlid)
	if err != nil {
		log.Error("Status: GetLicenseByDLID: %v", err)
		ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "internal error"})
		return
	}
	if license == nil {
		ctx.JSON(http.StatusNotFound, map[string]string{"error": "license not found"})
		return
	}

	// Get entitlements
	ents, err := licensing_model.GetEntitlementsByLicense(ctx, license.ID)
	if err != nil {
		log.Error("Status: GetEntitlementsByLicense: %v", err)
	}
	products := make([]string, 0, len(ents))
	for _, e := range ents {
		products = append(products, e.ProductCode)
	}

	// Get tier name
	tierName := license.Tier
	tier, _ := licensing_model.GetProductTierByKey(ctx, license.Tier)
	if tier != nil {
		tierName = tier.TierName
	}

	domainCount, _ := licensing_model.CountActivations(ctx, license.ID)

	resp := statusResponse{
		Valid:       license.IsActive(),
		DLID:        license.DLID,
		Tier:        license.Tier,
		TierName:    tierName,
		Status:      license.Status,
		Products:    products,
		DomainsUsed: int(domainCount),
		DomainsMax:  license.MaxDomains,
		CreatedAt:   time.Unix(int64(license.CreatedAt), 0).UTC().Format(time.RFC3339),
	}
	if license.ExpiresAt > 0 {
		resp.ExpiresAt = time.Unix(int64(license.ExpiresAt), 0).UTC().Format(time.RFC3339)
	}

	ctx.JSON(http.StatusOK, resp)
}
