package web

import (
	"encoding/json"
	"net/http"
	"sort"
	"time"

	"party.at/party/cmd/party/parlament"
	"party.at/party/cmd/party/common"
	"party.at/party/internal/data"
)

type parlVoteView struct {
	Date         string
	Title        string
	Number       string
	Type         string
	Topics       []string
	VotesFor     []string
	VotesAgainst []string
	RouteID      string
}

type parlTypeGroup struct {
	Code     string
	Label    string
	Docs     []parlVoteView
	HasVotes bool
}

type partyStat struct {
	Code    string
	For     int
	Against int
}


var typeLabels = map[string]string{
	"J":       "Schriftliche Anfrage",
	"M":       "Mündliche Anfrage",
	"JPR":     "Schriftliche Anfrage an Präsidium",
	"ABPR":    "Anfragebeantwortung Präsidium",
	"AB":      "Anfragebeantwortung",
	"A":       "Selbständiger Antrag",
	"A(E)":    "Selbständiger Entschließungsantrag",
	"AA":      "Abänderungsantrag im Plenum",
	"AAA":     "Abänderungsantrag im Ausschuss",
	"AEA":     "Selbständiger Ausschuss-Entschließungsantrag",
	"AUA":     "Ausschussbegutachtung",
	"AUB":     "Ausschussbericht",
	"UEA":     "Unselbständiger Entschließungsantrag",
	"EAA":     "Entschließungsantrag im Ausschuss",
	"E":       "Entschließung",
	"RV":      "Regierungsvorlage",
	"RVS":     "Regierungsvorlage: Staatsvertrag",
	"BNR":     "Beschluss des Nationalrates",
	"BS":      "Sonstiger Beschluss",
	"BUA":     "Bericht und Antrag",
	"BRG":     "Bericht der Bundesregierung",
	"BRH":     "Bericht des Rechnungshofs",
	"BRA":     "Bundesrechnungsabschluss",
	"BEU":     "Bericht der Bundesregierung zu EU-Themen",
	"BV":      "Bericht der Volksanwaltschaft",
	"BUV":     "Bericht des Unvereinbarkeitsausschusses",
	"BA":      "Vorlage für den Budgetausschuss",
	"BI":      "Bürgerinitiative",
	"PET":     "Petition",
	"VOLKBG":  "Volksbegehren",
	"IMM":     "Immunitätsangelegenheit",
	"AMIN":    "Selbständiger Antrag für eine Ministeranklage",
	"WA":      "Wahlvorgang/Abstimmungsvorgang",
	"WF":      "Wahl von Funktionsträgern",
	"WV":      "Ernennungsvorschlag",
	"RGER":    "Regierungserklärung im Plenum",
	"KOMM":    "Kommuniqué",
	"KOMMAUS": "Kommuniqué (Ausschuss)",
	"AS":      "Aktuelle Stunde",
	"ASEU":    "Aktuelle Europastunde",
	"FS":      "Fragestunde",
	"SINF":    "Schriftliche Information (§ 31c GOG-NR)",
	"TRAU":    "Trauerkundgebung",
	"USVL":    "Verlangen auf Einsetzung eines Untersuchungsausschusses",
	"FVUSE":   "Feststellung der Einsetzung eines Untersuchungsausschusses",
	"URH2":    "Verlangen auf Gebarungsüberprüfung (Rechnungshofausschuss)",
	"EUSV":    "Berichte über Sitzungen von vorbereitenden EU-Gremien",
	"EUBM":    "Berichte über Sitzungen des Europäischen Rates oder des Rates",
	"EUPA":    "Berichte über EP-Plenarsitzungen",
	"BEU2":    "Bericht der Bundesregierung zu EU-Themen",
	"GO01":    "Antrag auf erste Lesung",
	"GO04":    "Erklärung Präsidentin/Präsident",
	"GO05":    "Unterbrechung der Sitzung",
	"GO06":    "Wortmeldung zur Geschäftsbehandlung",
	"GO09":    "Ordnungsruf",
	"GO12":    "Einberufung einer Tagung",
	"GO13":    "Beendigung einer Tagung",
	"GO14":    "Antrag auf Fristsetzung für Bericht",
	"GO18":    "Gestaltung und Dauer der Redezeit",
	"GO20":    "Vorschlag Präsidium auf Durchführung einer Debatte",
	"GO32":    "Zuschrift",
	"GO35":    "Unterrichtung",
	"GO53":    "Antrag auf Rückverweisung",
	"GO67":    "Tatsächliche Berichtigung",
	"GO71":    "Aktionismus",
	"GO75":    "Antrag auf Nichtkenntnisnahme einer Anfragebeantwortung",
	"GO99":    "Sonstige Geschäftsordnungsangelegenheit",
}

func parseJSONStringArray(s string) []string {
	if s == "" {
		return nil
	}
	var out []string
	if err := json.Unmarshal([]byte(s), &out); err != nil {
		return nil
	}
	return out
}

func (web *Web) ParlVotesPage(w http.ResponseWriter, r *http.Request) {
	web.render(w, r, http.StatusOK, "parlvotes", struct {
		AuthenticatedUser *data.User
		Period            string
	}{
		AuthenticatedUser: common.GetUser(r),
		Period:            parlament.CurrentPeriod,
	})
}

func (web *Web) ParlVotesRowsFragment(w http.ResponseWriter, r *http.Request) {
	all, _, err := web.App.Parlament.ListDocuments(parlament.DocumentFilter{
		Chamber: []string{"NR"},
		Period:  []string{parlament.CurrentPeriod},
	})
	if err != nil {
		web.App.LogError(r, err)
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	// Build views, sorted by date descending.
	views := make([]parlVoteView, 0, len(all))
	for _, d := range all {
		views = append(views, parlVoteView{
			Date:         d.Date,
			Title:        d.Title,
			Number:       d.Number,
			Type:         d.Type,
			Topics:       parseJSONStringArray(d.Topics),
			VotesFor:     parseJSONStringArray(d.VotesFor),
			VotesAgainst: parseJSONStringArray(d.VotesAgainst),
			RouteID:      d.RouteID,
		})
	}
	sort.Slice(views, func(i, j int) bool {
		di, _ := time.Parse("02.01.2006", views[i].Date)
		dj, _ := time.Parse("02.01.2006", views[j].Date)
		return di.After(dj)
	})

	// Group by type, preserving insertion order for stable ordering.
	groupMap := make(map[string]*parlTypeGroup)
	var order []string
	for _, v := range views {
		if _, exists := groupMap[v.Type]; !exists {
			label := typeLabels[v.Type]
			if label == "" {
				label = v.Type
			}
			groupMap[v.Type] = &parlTypeGroup{Code: v.Type, Label: label}
			order = append(order, v.Type)
		}
		groupMap[v.Type].Docs = append(groupMap[v.Type].Docs, v)
		if len(v.VotesFor) > 0 || len(v.VotesAgainst) > 0 {
			groupMap[v.Type].HasVotes = true
		}
	}

	// Sort groups by size descending.
	sort.Slice(order, func(i, j int) bool {
		return len(groupMap[order[i]].Docs) > len(groupMap[order[j]].Docs)
	})

	groups := make([]parlTypeGroup, 0, len(order))
	for _, code := range order {
		groups = append(groups, *groupMap[code])
	}

	// Build vote summary.
	forCount := make(map[string]int)
	againstCount := make(map[string]int)
	totalVotes := 0
	for _, v := range views {
		if len(v.VotesFor) == 0 && len(v.VotesAgainst) == 0 {
			continue
		}
		totalVotes++
		for _, p := range v.VotesFor {
			forCount[p]++
		}
		for _, p := range v.VotesAgainst {
			againstCount[p]++
		}
	}
	seen := make(map[string]bool)
	var partyStats []partyStat
	for p := range forCount {
		seen[p] = true
	}
	for p := range againstCount {
		seen[p] = true
	}
	for code := range seen {
		partyStats = append(partyStats, partyStat{
			Code:    code,
			For:     forCount[code],
			Against: againstCount[code],
		})
	}
	sort.Slice(partyStats, func(i, j int) bool {
		ti := partyStats[i].For + partyStats[i].Against
		tj := partyStats[j].For + partyStats[j].Against
		if ti != tj {
			return ti > tj
		}
		return partyStats[i].Code < partyStats[j].Code
	})

	web.renderFragment(w, r, http.StatusOK, "parlvotesrows", struct {
		Groups     []parlTypeGroup
		TotalVotes int
		Parties    []partyStat
	}{
		Groups:     groups,
		TotalVotes: totalVotes,
		Parties:    partyStats,
	})
}
