package handlers

import (
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/breakpilot/ai-compliance-sdk/internal/funding"
	"github.com/breakpilot/ai-compliance-sdk/internal/llm"
	"github.com/breakpilot/ai-compliance-sdk/internal/rbac"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"gopkg.in/yaml.v3"
)

// FundingHandlers handles funding application API endpoints
type FundingHandlers struct {
	store            funding.Store
	providerRegistry *llm.ProviderRegistry
	wizardSchema     *WizardSchema
	bundeslandProfiles map[string]*BundeslandProfile
}

// WizardSchema represents the loaded wizard schema
type WizardSchema struct {
	Metadata struct {
		Version     string `yaml:"version"`
		Name        string `yaml:"name"`
		Description string `yaml:"description"`
		TotalSteps  int    `yaml:"total_steps"`
	} `yaml:"metadata"`
	Steps []WizardStep `yaml:"steps"`
	FundingAssistant struct {
		Enabled      bool              `yaml:"enabled"`
		Model        string            `yaml:"model"`
		SystemPrompt string            `yaml:"system_prompt"`
		StepContexts map[int]string    `yaml:"step_contexts"`
		QuickPrompts []QuickPrompt     `yaml:"quick_prompts"`
	} `yaml:"funding_assistant"`
	Presets map[string]Preset `yaml:"presets"`
}

// WizardStep represents a step in the wizard
type WizardStep struct {
	Number           int           `yaml:"number" json:"number"`
	ID               string        `yaml:"id" json:"id"`
	Title            string        `yaml:"title" json:"title"`
	Subtitle         string        `yaml:"subtitle" json:"subtitle"`
	Description      string        `yaml:"description" json:"description"`
	Icon             string        `yaml:"icon" json:"icon"`
	IsRequired       bool          `yaml:"is_required" json:"is_required"`
	Fields           []WizardField `yaml:"fields" json:"fields"`
	AssistantContext string        `yaml:"assistant_context" json:"assistant_context"`
}

// WizardField represents a field in the wizard
type WizardField struct {
	ID          string        `yaml:"id" json:"id"`
	Type        string        `yaml:"type" json:"type"`
	Label       string        `yaml:"label" json:"label"`
	Placeholder string        `yaml:"placeholder,omitempty" json:"placeholder,omitempty"`
	Required    bool          `yaml:"required,omitempty" json:"required,omitempty"`
	Options     []FieldOption `yaml:"options,omitempty" json:"options,omitempty"`
	HelpText    string        `yaml:"help_text,omitempty" json:"help_text,omitempty"`
	MaxLength   int           `yaml:"max_length,omitempty" json:"max_length,omitempty"`
	Min         *int          `yaml:"min,omitempty" json:"min,omitempty"`
	Max         *int          `yaml:"max,omitempty" json:"max,omitempty"`
	Default     interface{}   `yaml:"default,omitempty" json:"default,omitempty"`
	Conditional string        `yaml:"conditional,omitempty" json:"conditional,omitempty"`
}

// FieldOption represents an option for select fields
type FieldOption struct {
	Value       string `yaml:"value" json:"value"`
	Label       string `yaml:"label" json:"label"`
	Description string `yaml:"description,omitempty" json:"description,omitempty"`
}

// QuickPrompt represents a quick prompt for the assistant
type QuickPrompt struct {
	Label  string `yaml:"label" json:"label"`
	Prompt string `yaml:"prompt" json:"prompt"`
}

// Preset represents a BreakPilot preset
type Preset struct {
	ID          string                 `yaml:"id" json:"id"`
	Name        string                 `yaml:"name" json:"name"`
	Description string                 `yaml:"description" json:"description"`
	BudgetItems []funding.BudgetItem   `yaml:"budget_items" json:"budget_items"`
	AutoFill    map[string]interface{} `yaml:"auto_fill" json:"auto_fill"`
}

// BundeslandProfile represents a federal state profile
type BundeslandProfile struct {
	Name                string          `yaml:"name" json:"name"`
	Short               string          `yaml:"short" json:"short"`
	FundingPrograms     []string        `yaml:"funding_programs" json:"funding_programs"`
	DefaultFundingRate  float64         `yaml:"default_funding_rate" json:"default_funding_rate"`
	RequiresMEP         bool            `yaml:"requires_mep" json:"requires_mep"`
	ContactAuthority    ContactAuthority `yaml:"contact_authority" json:"contact_authority"`
	SpecialRequirements []string        `yaml:"special_requirements" json:"special_requirements"`
}

// ContactAuthority represents a contact authority
type ContactAuthority struct {
	Name       string `yaml:"name" json:"name"`
	Department string `yaml:"department,omitempty" json:"department,omitempty"`
	Website    string `yaml:"website" json:"website"`
	Email      string `yaml:"email,omitempty" json:"email,omitempty"`
}

// NewFundingHandlers creates new funding handlers
func NewFundingHandlers(store funding.Store, providerRegistry *llm.ProviderRegistry) *FundingHandlers {
	h := &FundingHandlers{
		store:            store,
		providerRegistry: providerRegistry,
	}

	// Load wizard schema
	if err := h.loadWizardSchema(); err != nil {
		fmt.Printf("Warning: Could not load wizard schema: %v\n", err)
	}

	// Load bundesland profiles
	if err := h.loadBundeslandProfiles(); err != nil {
		fmt.Printf("Warning: Could not load bundesland profiles: %v\n", err)
	}

	return h
}

func (h *FundingHandlers) loadWizardSchema() error {
	data, err := os.ReadFile("policies/funding/foerderantrag_wizard_v1.yaml")
	if err != nil {
		return err
	}

	h.wizardSchema = &WizardSchema{}
	return yaml.Unmarshal(data, h.wizardSchema)
}

func (h *FundingHandlers) loadBundeslandProfiles() error {
	data, err := os.ReadFile("policies/funding/bundesland_profiles.yaml")
	if err != nil {
		return err
	}

	var profiles struct {
		Bundeslaender map[string]*BundeslandProfile `yaml:"bundeslaender"`
	}
	if err := yaml.Unmarshal(data, &profiles); err != nil {
		return err
	}

	h.bundeslandProfiles = profiles.Bundeslaender
	return nil
}

// ============================================================================
// Application CRUD
// ============================================================================

// CreateApplication creates a new funding application
// POST /sdk/v1/funding/applications
func (h *FundingHandlers) CreateApplication(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	userID := rbac.GetUserID(c)
	if tenantID == uuid.Nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
		return
	}

	var req funding.CreateApplicationRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	app := &funding.FundingApplication{
		TenantID:       tenantID,
		Title:          req.Title,
		FundingProgram: req.FundingProgram,
		Status:         funding.ApplicationStatusDraft,
		CurrentStep:    1,
		TotalSteps:     8,
		WizardData:     make(map[string]interface{}),
		CreatedBy:      userID,
		UpdatedBy:      userID,
	}

	// Initialize school profile with federal state
	app.SchoolProfile = &funding.SchoolProfile{
		FederalState: req.FederalState,
	}

	// Apply preset if specified
	if req.PresetID != "" && h.wizardSchema != nil {
		if preset, ok := h.wizardSchema.Presets[req.PresetID]; ok {
			app.Budget = &funding.Budget{
				BudgetItems: preset.BudgetItems,
			}
			app.WizardData["preset_id"] = req.PresetID
			app.WizardData["preset_applied"] = true
			for k, v := range preset.AutoFill {
				app.WizardData[k] = v
			}
		}
	}

	if err := h.store.CreateApplication(c.Request.Context(), app); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Add history entry
	h.store.AddHistoryEntry(c.Request.Context(), &funding.ApplicationHistoryEntry{
		ApplicationID: app.ID,
		Action:        "created",
		PerformedBy:   userID,
		Notes:         "Antrag erstellt",
	})

	c.JSON(http.StatusCreated, app)
}

// GetApplication retrieves a funding application
// GET /sdk/v1/funding/applications/:id
func (h *FundingHandlers) GetApplication(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid application ID"})
		return
	}

	app, err := h.store.GetApplication(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, app)
}

// ListApplications returns a list of funding applications
// GET /sdk/v1/funding/applications
func (h *FundingHandlers) ListApplications(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	if tenantID == uuid.Nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
		return
	}

	filter := funding.ApplicationFilter{
		Page:     1,
		PageSize: 20,
	}

	// Parse query parameters
	if status := c.Query("status"); status != "" {
		s := funding.ApplicationStatus(status)
		filter.Status = &s
	}
	if program := c.Query("program"); program != "" {
		p := funding.FundingProgram(program)
		filter.FundingProgram = &p
	}

	result, err := h.store.ListApplications(c.Request.Context(), tenantID, filter)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, result)
}

// UpdateApplication updates a funding application
// PUT /sdk/v1/funding/applications/:id
func (h *FundingHandlers) UpdateApplication(c *gin.Context) {
	userID := rbac.GetUserID(c)
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid application ID"})
		return
	}

	app, err := h.store.GetApplication(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	var req funding.UpdateApplicationRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if req.Title != nil {
		app.Title = *req.Title
	}
	if req.WizardData != nil {
		for k, v := range req.WizardData {
			app.WizardData[k] = v
		}
	}
	if req.CurrentStep != nil {
		app.CurrentStep = *req.CurrentStep
	}
	app.UpdatedBy = userID

	if err := h.store.UpdateApplication(c.Request.Context(), app); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, app)
}

// DeleteApplication deletes a funding application
// DELETE /sdk/v1/funding/applications/:id
func (h *FundingHandlers) DeleteApplication(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid application ID"})
		return
	}

	if err := h.store.DeleteApplication(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "application archived"})
}

// ============================================================================
// Wizard Endpoints
// ============================================================================

// GetWizardSchema returns the wizard schema
// GET /sdk/v1/funding/wizard/schema
func (h *FundingHandlers) GetWizardSchema(c *gin.Context) {
	if h.wizardSchema == nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "wizard schema not loaded"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"metadata": h.wizardSchema.Metadata,
		"steps":    h.wizardSchema.Steps,
		"presets":  h.wizardSchema.Presets,
		"assistant": gin.H{
			"enabled":       h.wizardSchema.FundingAssistant.Enabled,
			"quick_prompts": h.wizardSchema.FundingAssistant.QuickPrompts,
		},
	})
}

// SaveWizardStep saves wizard step data
// POST /sdk/v1/funding/applications/:id/wizard
func (h *FundingHandlers) SaveWizardStep(c *gin.Context) {
	userID := rbac.GetUserID(c)
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid application ID"})
		return
	}

	var req funding.SaveWizardStepRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Save step data
	if err := h.store.SaveWizardStep(c.Request.Context(), id, req.Step, req.Data); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Get updated progress
	progress, err := h.store.GetWizardProgress(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Add history entry
	h.store.AddHistoryEntry(c.Request.Context(), &funding.ApplicationHistoryEntry{
		ApplicationID: id,
		Action:        "wizard_step_saved",
		PerformedBy:   userID,
		Notes:         fmt.Sprintf("Schritt %d gespeichert", req.Step),
	})

	c.JSON(http.StatusOK, progress)
}

// AskAssistant handles LLM assistant queries
// POST /sdk/v1/funding/wizard/ask
func (h *FundingHandlers) AskAssistant(c *gin.Context) {
	var req funding.AssistantRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if h.wizardSchema == nil || !h.wizardSchema.FundingAssistant.Enabled {
		c.JSON(http.StatusServiceUnavailable, gin.H{"error": "assistant not available"})
		return
	}

	// Build system prompt with step context
	systemPrompt := h.wizardSchema.FundingAssistant.SystemPrompt
	if stepContext, ok := h.wizardSchema.FundingAssistant.StepContexts[req.CurrentStep]; ok {
		systemPrompt += "\n\nKontext fuer diesen Schritt:\n" + stepContext
	}

	// Build messages
	messages := []llm.Message{
		{Role: "system", Content: systemPrompt},
	}
	for _, msg := range req.History {
		messages = append(messages, llm.Message{
			Role:    msg.Role,
			Content: msg.Content,
		})
	}
	messages = append(messages, llm.Message{
		Role:    "user",
		Content: req.Question,
	})

	// Generate response using registry
	chatReq := &llm.ChatRequest{
		Messages:    messages,
		Temperature: 0.3,
		MaxTokens:   1000,
	}

	response, err := h.providerRegistry.Chat(c.Request.Context(), chatReq)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, funding.AssistantResponse{
		Answer: response.Message.Content,
	})
}

// ============================================================================
// Status Endpoints
// ============================================================================

// SubmitApplication submits an application for review
// POST /sdk/v1/funding/applications/:id/submit
func (h *FundingHandlers) SubmitApplication(c *gin.Context) {
	userID := rbac.GetUserID(c)
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid application ID"})
		return
	}

	app, err := h.store.GetApplication(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	// Validate that all required steps are completed
	progress, _ := h.store.GetWizardProgress(c.Request.Context(), id)
	if progress == nil || len(progress.CompletedSteps) < app.TotalSteps {
		c.JSON(http.StatusBadRequest, gin.H{"error": "not all required steps completed"})
		return
	}

	// Update status
	app.Status = funding.ApplicationStatusSubmitted
	now := time.Now()
	app.SubmittedAt = &now
	app.UpdatedBy = userID

	if err := h.store.UpdateApplication(c.Request.Context(), app); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Add history entry
	h.store.AddHistoryEntry(c.Request.Context(), &funding.ApplicationHistoryEntry{
		ApplicationID: id,
		Action:        "submitted",
		PerformedBy:   userID,
		Notes:         "Antrag eingereicht",
	})

	c.JSON(http.StatusOK, app)
}

// ============================================================================
// Export Endpoints
// ============================================================================

// ExportApplication exports all documents as ZIP
// GET /sdk/v1/funding/applications/:id/export
func (h *FundingHandlers) ExportApplication(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid application ID"})
		return
	}

	app, err := h.store.GetApplication(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	// Generate export (this will be implemented in export.go)
	// For now, return a placeholder response
	c.JSON(http.StatusOK, gin.H{
		"message":        "Export generation initiated",
		"application_id": app.ID,
		"status":         "processing",
	})
}

// PreviewApplication generates a PDF preview
// GET /sdk/v1/funding/applications/:id/preview
func (h *FundingHandlers) PreviewApplication(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid application ID"})
		return
	}

	app, err := h.store.GetApplication(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	// Generate PDF preview (placeholder)
	c.JSON(http.StatusOK, gin.H{
		"message":        "Preview generation initiated",
		"application_id": app.ID,
	})
}

// ============================================================================
// Bundesland Profile Endpoints
// ============================================================================

// GetBundeslandProfiles returns all bundesland profiles
// GET /sdk/v1/funding/bundeslaender
func (h *FundingHandlers) GetBundeslandProfiles(c *gin.Context) {
	if h.bundeslandProfiles == nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "bundesland profiles not loaded"})
		return
	}

	c.JSON(http.StatusOK, h.bundeslandProfiles)
}

// GetBundeslandProfile returns a specific bundesland profile
// GET /sdk/v1/funding/bundeslaender/:state
func (h *FundingHandlers) GetBundeslandProfile(c *gin.Context) {
	state := c.Param("state")

	if h.bundeslandProfiles == nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "bundesland profiles not loaded"})
		return
	}

	profile, ok := h.bundeslandProfiles[state]
	if !ok {
		c.JSON(http.StatusNotFound, gin.H{"error": "bundesland not found"})
		return
	}

	c.JSON(http.StatusOK, profile)
}

// ============================================================================
// Statistics Endpoint
// ============================================================================

// GetStatistics returns funding statistics
// GET /sdk/v1/funding/statistics
func (h *FundingHandlers) GetStatistics(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	if tenantID == uuid.Nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
		return
	}

	stats, err := h.store.GetStatistics(c.Request.Context(), tenantID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, stats)
}

// ============================================================================
// History Endpoint
// ============================================================================

// GetApplicationHistory returns the audit trail
// GET /sdk/v1/funding/applications/:id/history
func (h *FundingHandlers) GetApplicationHistory(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid application ID"})
		return
	}

	history, err := h.store.GetHistory(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, history)
}
