package licensing

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

	"github.com/google/uuid"
	"github.com/rs/zerolog/log"
)

// EnterpriseValidator handles validation of enterprise licenses via KACHING
type EnterpriseValidator struct {
	kachingEndpoint string
	client          *http.Client
	cache           *LicenseCache
}

// LicenseFeatures represents the features available in a license
type LicenseFeatures struct {
	SpecKitMethodology bool                   `json:"spec_kit_methodology"`
	CustomTemplates    bool                   `json:"custom_templates"`
	AdvancedAnalytics  bool                   `json:"advanced_analytics"`
	WorkflowQuota      int                    `json:"workflow_quota"`
	PrioritySupport    bool                   `json:"priority_support"`
	Additional         map[string]interface{} `json:"additional,omitempty"`
}

// LicenseInfo contains validated license information
type LicenseInfo struct {
	LicenseID      uuid.UUID        `json:"license_id"`
	OrgID          uuid.UUID        `json:"org_id"`
	DeploymentID   uuid.UUID        `json:"deployment_id"`
	PlanID         string           `json:"plan_id"` // community, professional, enterprise
	Features       LicenseFeatures  `json:"features"`
	ValidFrom      time.Time        `json:"valid_from"`
	ValidTo        time.Time        `json:"valid_to"`
	SeatsLimit     *int             `json:"seats_limit,omitempty"`
	NodesLimit     *int             `json:"nodes_limit,omitempty"`
	IsValid        bool             `json:"is_valid"`
	ValidationTime time.Time        `json:"validation_time"`
}

// ValidationRequest sent to KACHING for license validation
type ValidationRequest struct {
	DeploymentID uuid.UUID `json:"deployment_id"`
	Feature      string    `json:"feature"` // e.g., "spec_kit_methodology"
	Context      Context   `json:"context"`
}

// Context provides additional information for license validation
type Context struct {
	ProjectID   string `json:"project_id,omitempty"`
	IssueID     string `json:"issue_id,omitempty"`
	CouncilID   string `json:"council_id,omitempty"`
	RequestedBy string `json:"requested_by,omitempty"`
}

// ValidationResponse from KACHING
type ValidationResponse struct {
	Valid        bool          `json:"valid"`
	License      *LicenseInfo  `json:"license,omitempty"`
	Reason       string        `json:"reason,omitempty"`
	UsageInfo    *UsageInfo    `json:"usage_info,omitempty"`
	Suggestions  []Suggestion  `json:"suggestions,omitempty"`
}

// UsageInfo provides current usage statistics
type UsageInfo struct {
	CurrentMonth struct {
		SpecKitWorkflows int `json:"spec_kit_workflows"`
		Quota            int `json:"quota"`
		Remaining        int `json:"remaining"`
	} `json:"current_month"`
	PreviousMonth struct {
		SpecKitWorkflows int `json:"spec_kit_workflows"`
	} `json:"previous_month"`
}

// Suggestion for license upgrades
type Suggestion struct {
	Type        string            `json:"type"`        // upgrade_tier, enable_feature
	Title       string            `json:"title"`
	Description string            `json:"description"`
	TargetPlan  string            `json:"target_plan,omitempty"`
	Benefits    map[string]string `json:"benefits,omitempty"`
}

// NewEnterpriseValidator creates a new enterprise license validator
func NewEnterpriseValidator(kachingEndpoint string) *EnterpriseValidator {
	return &EnterpriseValidator{
		kachingEndpoint: kachingEndpoint,
		client: &http.Client{
			Timeout: 10 * time.Second,
		},
		cache: NewLicenseCache(5 * time.Minute), // 5-minute cache TTL
	}
}

// ValidateSpecKitAccess validates if a deployment has access to spec-kit features
func (v *EnterpriseValidator) ValidateSpecKitAccess(
	ctx context.Context,
	deploymentID uuid.UUID,
	context Context,
) (*ValidationResponse, error) {
	startTime := time.Now()

	log.Info().
		Str("deployment_id", deploymentID.String()).
		Str("feature", "spec_kit_methodology").
		Msg("Validating spec-kit access")

	// Check cache first
	if cached := v.cache.Get(deploymentID, "spec_kit_methodology"); cached != nil {
		log.Debug().
			Str("deployment_id", deploymentID.String()).
			Msg("Using cached license validation")
		return cached, nil
	}

	// Prepare validation request
	request := ValidationRequest{
		DeploymentID: deploymentID,
		Feature:      "spec_kit_methodology",
		Context:      context,
	}

	response, err := v.callKachingValidation(ctx, request)
	if err != nil {
		log.Error().
			Err(err).
			Str("deployment_id", deploymentID.String()).
			Msg("Failed to validate license with KACHING")
		return nil, fmt.Errorf("license validation failed: %w", err)
	}

	// Cache successful responses
	if response.Valid {
		v.cache.Set(deploymentID, "spec_kit_methodology", response)
	}

	duration := time.Since(startTime).Milliseconds()
	log.Info().
		Str("deployment_id", deploymentID.String()).
		Bool("valid", response.Valid).
		Int64("duration_ms", duration).
		Msg("License validation completed")

	return response, nil
}

// ValidateWorkflowQuota checks if deployment has remaining spec-kit workflow quota
func (v *EnterpriseValidator) ValidateWorkflowQuota(
	ctx context.Context,
	deploymentID uuid.UUID,
	context Context,
) (*ValidationResponse, error) {
	// First validate basic access
	response, err := v.ValidateSpecKitAccess(ctx, deploymentID, context)
	if err != nil {
		return nil, err
	}

	if !response.Valid {
		return response, nil
	}

	// Check quota specifically
	if response.UsageInfo != nil {
		remaining := response.UsageInfo.CurrentMonth.Remaining
		if remaining <= 0 {
			response.Valid = false
			response.Reason = "Monthly spec-kit workflow quota exceeded"

			// Add upgrade suggestion if quota exceeded
			if response.License != nil && response.License.PlanID == "professional" {
				response.Suggestions = append(response.Suggestions, Suggestion{
					Type:        "upgrade_tier",
					Title:       "Upgrade to Enterprise",
					Description: "Get unlimited spec-kit workflows with Enterprise tier",
					TargetPlan:  "enterprise",
					Benefits: map[string]string{
						"workflows": "Unlimited spec-kit workflows",
						"templates": "Custom template library access",
						"support":   "24/7 priority support",
					},
				})
			}
		}
	}

	return response, nil
}

// GetLicenseInfo retrieves complete license information for a deployment
func (v *EnterpriseValidator) GetLicenseInfo(
	ctx context.Context,
	deploymentID uuid.UUID,
) (*LicenseInfo, error) {
	response, err := v.ValidateSpecKitAccess(ctx, deploymentID, Context{})
	if err != nil {
		return nil, err
	}

	return response.License, nil
}

// IsEnterpriseFeatureEnabled checks if a specific enterprise feature is enabled
func (v *EnterpriseValidator) IsEnterpriseFeatureEnabled(
	ctx context.Context,
	deploymentID uuid.UUID,
	feature string,
) (bool, error) {
	request := ValidationRequest{
		DeploymentID: deploymentID,
		Feature:      feature,
		Context:      Context{},
	}

	response, err := v.callKachingValidation(ctx, request)
	if err != nil {
		return false, err
	}

	return response.Valid, nil
}

// callKachingValidation makes HTTP request to KACHING validation endpoint
func (v *EnterpriseValidator) callKachingValidation(
	ctx context.Context,
	request ValidationRequest,
) (*ValidationResponse, error) {
	// Prepare HTTP request
	requestBody, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	url := fmt.Sprintf("%s/v1/license/validate", v.kachingEndpoint)
	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(requestBody))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", "WHOOSH/1.0")

	// Make request
	resp, err := v.client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	// Handle different response codes
	switch resp.StatusCode {
	case http.StatusOK:
		var response ValidationResponse
		if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
			return nil, fmt.Errorf("failed to decode response: %w", err)
		}
		return &response, nil

	case http.StatusUnauthorized:
		return &ValidationResponse{
			Valid:  false,
			Reason: "Invalid or expired license",
		}, nil

	case http.StatusTooManyRequests:
		return &ValidationResponse{
			Valid:  false,
			Reason: "Rate limit exceeded",
		}, nil

	case http.StatusServiceUnavailable:
		// KACHING service unavailable - fallback to cached or basic validation
		log.Warn().
			Str("deployment_id", request.DeploymentID.String()).
			Msg("KACHING service unavailable, falling back to basic validation")

		return v.fallbackValidation(request.DeploymentID)

	default:
		return nil, fmt.Errorf("unexpected response status: %d", resp.StatusCode)
	}
}

// fallbackValidation provides basic validation when KACHING is unavailable
func (v *EnterpriseValidator) fallbackValidation(deploymentID uuid.UUID) (*ValidationResponse, error) {
	// Check cache for any recent validation
	if cached := v.cache.Get(deploymentID, "spec_kit_methodology"); cached != nil {
		log.Info().
			Str("deployment_id", deploymentID.String()).
			Msg("Using cached license data for fallback validation")
		return cached, nil
	}

	// Default to basic access for community features
	return &ValidationResponse{
		Valid:  false, // Spec-kit is enterprise only
		Reason: "License service unavailable - spec-kit requires enterprise license",
		Suggestions: []Suggestion{
			{
				Type:        "contact_support",
				Title:       "Contact Support",
				Description: "License service is temporarily unavailable. Contact support for assistance.",
			},
		},
	}, nil
}

// TrackWorkflowUsage reports spec-kit workflow usage to KACHING for billing
func (v *EnterpriseValidator) TrackWorkflowUsage(
	ctx context.Context,
	deploymentID uuid.UUID,
	workflowType string,
	metadata map[string]interface{},
) error {
	usageEvent := map[string]interface{}{
		"deployment_id": deploymentID,
		"event_type":    "spec_kit_workflow_executed",
		"workflow_type": workflowType,
		"timestamp":     time.Now().UTC(),
		"metadata":      metadata,
	}

	eventData, err := json.Marshal(usageEvent)
	if err != nil {
		return fmt.Errorf("failed to marshal usage event: %w", err)
	}

	url := fmt.Sprintf("%s/v1/usage/track", v.kachingEndpoint)
	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(eventData))
	if err != nil {
		return fmt.Errorf("failed to create usage tracking request: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := v.client.Do(req)
	if err != nil {
		// Log error but don't fail the workflow for usage tracking issues
		log.Error().
			Err(err).
			Str("deployment_id", deploymentID.String()).
			Str("workflow_type", workflowType).
			Msg("Failed to track workflow usage")
		return nil
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		log.Error().
			Int("status_code", resp.StatusCode).
			Str("deployment_id", deploymentID.String()).
			Msg("Usage tracking request failed")
	}

	return nil
}