package parlament

// Parliamentarian is a member of the Austrian parliament (dataset 409, historical).
type Parliamentarian struct {
	Name         string
	Faction      string // "Klub/Fraktion" column
	Period       string // "Gesetzgebungsperiode" column
	Constituency string // "Wahlkreis" column
	// Path is the portal-relative URL, usable with Client.GetDetail.
	Path string // "Bio" column
}

type ParliamentarianFilter struct {
	// Period is the legislative period in Roman numerals, e.g. "XXVIII".
	// Maps to the gp_text_full_short filter dimension.
	Period []string
}

// ListParliamentarians returns MPs matching the given filter (dataset 409, all periods).
func (c *Client) ListParliamentarians(f ParliamentarianFilter) ([]Parliamentarian, int, error) {
	payload := map[string]any{}
	if len(f.Period) > 0 {
		payload["gp_text_full_short"] = f.Period
	}

	resp, err := c.postDataset(409, payload)
	if err != nil {
		return nil, 0, err
	}

	idx := colIndex(resp.Header)
	mps := make([]Parliamentarian, 0, len(resp.Rows))
	for _, row := range resp.Rows {
		mps = append(mps, Parliamentarian{
			Name:         strCol(row, idx, "Name"),
			Faction:      strCol(row, idx, "Klub/Fraktion"),
			Period:       strCol(row, idx, "Gesetzgebungsperiode"),
			Constituency: strCol(row, idx, "Wahlkreis"),
			Path:         strCol(row, idx, "Bio"),
		})
	}
	return mps, resp.Count, nil
}

// Member is a richer parliamentarian record, which supports filtering by
// active status, legislative period, and parliamentary body.
type Member struct {
	Name         string // "Nachname Vorname" format
	FirstName    string
	LastName     string
	Faction      string // party abbreviation, e.g. "FPÖ"
	FractionName string // full parliamentary club name, e.g. "Freiheitlicher Parlamentsklub"
	Role         string // current role, e.g. "Abgeordnete zum Nationalrat"
	Constituency string // "Wahlkreis"
	// PhotoURL is the partial image path (prepend baseURL to resolve).
	PhotoURL string // e.g. "/dokument/bild/201448/20144872_180.jpg"
	// Path is the portal-relative biography URL, usable with Client.GetDetail.
	Path   string
	Active bool
}

// MemberType distinguishes the kind of parliamentary mandate.
const (
	MemberTypeNR    = "NR"    // Nationalrat deputy
	MemberTypeBR    = "BR"    // Bundesrat member
	MemberTypePres  = "MPO"   // President / Vice-President
	MemberTypeGovt  = "BuREG" // Federal government member
)

type MemberFilter struct {
	// Period is the legislative period, e.g. "XXVIII".
	Period []string
	// Active, when true, restricts to currently serving members.
	Active bool
	// Type filters by mandate kind (MemberTypeNR, MemberTypeBR, etc.).
	Type []string
	// Faction filters by party abbreviation, e.g. "FPÖ".
	Faction []string
}

// ListMembers returns parliamentary members using dataset 401, which supports
// richer filtering than ListParliamentarians (active status, mandate type).
func (c *Client) ListMembers(f MemberFilter) ([]Member, int, error) {
	payload := map[string]any{}
	if len(f.Period) > 0 {
		payload["GP_CODE"] = f.Period
	}
	if f.Active {
		payload["AKTIV"] = []string{"J"}
	}
	if len(f.Type) > 0 {
		payload["persart"] = f.Type
	}
	if len(f.Faction) > 0 {
		payload["frak"] = f.Faction
	}

	resp, err := c.postDataset(401, payload)
	if err != nil {
		return nil, 0, err
	}

	idx := colIndex(resp.Header)
	members := make([]Member, 0, len(resp.Rows))
	for _, row := range resp.Rows {
		members = append(members, Member{
			Name:         strCol(row, idx, "Name"),
			FirstName:    strCol(row, idx, "vorname"),
			LastName:     strCol(row, idx, "nachname"),
			Faction:      strCol(row, idx, "frak"),
			Role:         strCol(row, idx, "Funktion"),
			Constituency: strCol(row, idx, "Wahlkreis"),
			PhotoURL:     strCol(row, idx, "Image"),
			Path:         strCol(row, idx, "link"),
			Active:       strCol(row, idx, "aktiv") == "J",
		})
	}
	return members, resp.Count, nil
}

// ListNRMembers returns active Nationalrat deputies for the given legislative
// period, including each member's full parliamentary Fraktion (club) name.
// It fetches from dataset 409 and filters client-side because that dataset's
// nested Attribute object is the only source for the proper Fraktion name.
func (c *Client) ListNRMembers(period string) ([]Member, error) {
	resp, err := c.postDataset(409, map[string]any{})
	if err != nil {
		return nil, err
	}

	idx := colIndex(resp.Header)
	var members []Member
	for _, row := range resp.Rows {
		attr, _ := anyCol(row, idx, "Attribute").(map[string]any)
		if attr == nil {
			continue
		}

		// Keep only active members of the requested period.
		if active, _ := attr["aktiv"].(bool); !active {
			continue
		}
		gpCodes, _ := attr["gp_code"].([]any)
		inPeriod := false
		for _, gp := range gpCodes {
			if gp == period {
				inPeriod = true
				break
			}
		}
		if !inPeriod {
			continue
		}

		// Find the NR mandate for this period to get the Fraktion name.
		faction, fractionName := "", ""
		mandates, _ := attr["mandate_detail"].([]any)
		for _, m := range mandates {
			mandate, _ := m.(map[string]any)
			if mandate == nil {
				continue
			}
			if mandate["gp_code"] == period && mandate["mand_code"] == "NR" {
				faction, _ = mandate["wahlpartei_code"].(string)
				fractionName, _ = mandate["fraktion"].(string)
				break
			}
		}
		if fractionName == "" {
			continue // not an NR mandate in this period
		}

		members = append(members, Member{
			Name:         strCol(row, idx, "Name"),
			FirstName:    strCol(row, idx, "vorname"),
			LastName:     strCol(row, idx, "nachname"),
			Faction:      faction,
			FractionName: fractionName,
			Constituency: strCol(row, idx, "Wahlkreis"),
			Path:         strCol(row, idx, "Bio"),
			Active:       true,
		})
	}
	return members, nil
}
