package controllers

import (
	"encoding/json"
	"fmt"
	"maps"
	"slices"
	"strings"

	"github.com/Theodor-Springmann-Stiftung/kgpz_web/xmlmodels"
	"github.com/gofiber/fiber/v2"
)

// GetQuickFilter handles the request to display the quick filter interface
func GetQuickFilter(kgpz *xmlmodels.Library) fiber.Handler {
	return func(c *fiber.Ctx) error {
		// Get all available years and issues for filters
		years := make(map[int]bool)
		issuesByYear := make(map[int][]IssueSummary)

		kgpz.Issues.Lock()
		for _, issue := range kgpz.Issues.Array {
			year := issue.Datum.When.Year
			years[year] = true

			// Format date for display (DD.MM.YYYY)
			dateStr := fmt.Sprintf("%02d.%02d.%d",
				issue.Datum.When.Day,
				issue.Datum.When.Month,
				issue.Datum.When.Year)

			issueSummary := IssueSummary{
				Number: issue.Number.No,
				Date:   dateStr,
			}

			issuesByYear[year] = append(issuesByYear[year], issueSummary)
		}
		kgpz.Issues.Unlock()

		// Convert map to sorted slice using the same approach as year_view.go
		availableYears := slices.Collect(maps.Keys(years))
		slices.Sort(availableYears)

		// Sort issues within each year by issue number
		for year := range issuesByYear {
			slices.SortFunc(issuesByYear[year], func(a, b IssueSummary) int {
				return a.Number - b.Number
			})
		}

		// Convert issuesByYear to JSON string for the web component
		issuesByYearJSON, err := json.Marshal(issuesByYear)
		if err != nil {
			issuesByYearJSON = []byte("{}")
		}

		// Get all persons and identify authors
		persons := make([]PersonSummary, 0)
		authors := make([]PersonSummary, 0)

		// Find all agents who have pieces (same logic as AuthorsView)
		authorIDs := make(map[string]bool)
		for _, piece := range kgpz.Pieces.Array {
			for _, agentRef := range piece.AgentRefs {
				if agentRef.Category == "" || agentRef.Category == "autor" {
					authorIDs[agentRef.Ref] = true
				}
			}
		}

		kgpz.Agents.Lock()
		for _, agent := range kgpz.Agents.Array {
			// Get the primary name (first name in the list)
			var name string
			if len(agent.Names) > 0 {
				name = agent.Names[0]
			} else {
				name = agent.ID // fallback to ID if no names
			}

			person := PersonSummary{
				ID:   agent.ID,
				Name: name,
				Life: agent.Life,
			}

			persons = append(persons, person)

			// Add to authors list if this person is an author
			if authorIDs[agent.ID] {
				authors = append(authors, person)
			}
		}
		kgpz.Agents.Unlock()

		// Sort both lists by ID
		slices.SortFunc(persons, func(a, b PersonSummary) int {
			return strings.Compare(a.ID, b.ID)
		})
		slices.SortFunc(authors, func(a, b PersonSummary) int {
			return strings.Compare(a.ID, b.ID)
		})

		// Get all places that are referenced in pieces
		places := make([]PlaceSummary, 0)
		referencedPlaces := make(map[string]bool)

		for _, piece := range kgpz.Pieces.Array {
			for _, placeRef := range piece.PlaceRefs {
				referencedPlaces[placeRef.Ref] = true
			}
		}

		kgpz.Places.Lock()
		for _, place := range kgpz.Places.Array {
			// Only include places that are actually referenced in pieces
			if referencedPlaces[place.ID] {
				// Get the primary name (first name in the list)
				var name string
				if len(place.Names) > 0 {
					name = place.Names[0]
				} else {
					name = place.ID // fallback to ID if no names
				}

				placeSummary := PlaceSummary{
					ID:   place.ID,
					Name: name,
					Geo:  place.Geo,
				}

				places = append(places, placeSummary)
			}
		}
		kgpz.Places.Unlock()

		// Sort places list by ID
		slices.SortFunc(places, func(a, b PlaceSummary) int {
			return strings.Compare(a.ID, b.ID)
		})

		// Get all categories with their first available year
		categories := make([]CategorySummary, 0)
		categoryYears := make(map[string][]int) // categoryID -> list of years

		// First pass: collect all years for each category
		for _, piece := range kgpz.Pieces.Array {
			// Get years for this piece
			pieceYears := make(map[int]bool)
			for _, issueRef := range piece.IssueRefs {
				if issueRef.When.Year > 0 {
					pieceYears[issueRef.When.Year] = true
				}
			}

			// Process CategoryRefs
			for _, catRef := range piece.CategoryRefs {
				if catRef.Ref != "" {
					for year := range pieceYears {
						categoryYears[catRef.Ref] = append(categoryYears[catRef.Ref], year)
					}
				}
			}

			// Process WorkRefs with categories (rezension)
			for _, workRef := range piece.WorkRefs {
				categoryID := workRef.Category
				if categoryID == "" {
					categoryID = "rezension" // Default category for WorkRefs
				}
				for year := range pieceYears {
					categoryYears[categoryID] = append(categoryYears[categoryID], year)
				}
			}
		}

		// Build categories list with first year for each
		kgpz.Categories.Lock()
		for _, category := range kgpz.Categories.Array {
			if yearsList, exists := categoryYears[category.ID]; exists && len(yearsList) > 0 {
				// Find the earliest year for this category
				slices.Sort(yearsList)
				firstYear := yearsList[0]

				// Get the primary name (first name in the list)
				var name string
				if len(category.Names) > 0 {
					name = category.Names[0]
				} else {
					name = category.ID // fallback to ID if no names
				}

				categorySummary := CategorySummary{
					ID:        category.ID,
					Name:      name,
					FirstYear: firstYear,
				}

				categories = append(categories, categorySummary)
			}
		}
		kgpz.Categories.Unlock()

		// Sort categories list by name
		slices.SortFunc(categories, func(a, b CategorySummary) int {
			return strings.Compare(a.Name, b.Name)
		})

		// Prepare data for the filter template
		data := fiber.Map{
			"AvailableYears":    availableYears,
			"Persons":           persons,
			"Authors":           authors,
			"Places":            places,
			"Categories":        categories,
			"IssuesByYearJSON":  string(issuesByYearJSON),
		}

		// Render the filter body using clear layout (no page layout)
		return c.Render("/filter/", data, "clear")
	}
}

// PersonSummary represents a simplified person for the filter list
type PersonSummary struct {
	ID   string
	Name string
	Life string
}

// PlaceSummary represents a simplified place for the filter list
type PlaceSummary struct {
	ID   string
	Name string
	Geo  string
}

// CategorySummary represents a simplified category for the filter list
type CategorySummary struct {
	ID        string
	Name      string
	FirstYear int
}

// IssueSummary represents an issue for the Jahr/Ausgabe filter
type IssueSummary struct {
	Number int    `json:"number"`
	Date   string `json:"date"`
}