using System;
using System.Collections.Generic;
using System.Linq;

namespace Tornado3_2026Election.Domain;

public sealed class ElectionDataSnapshot
{
    public required BroadcastPhase BroadcastPhase { get; init; }

    public required string ElectionType { get; init; }

    public required string DistrictName { get; init; }

    public required string DistrictCode { get; init; }

    public required string RegionName { get; init; }

    public required string ElectionDistrictName { get; init; }

    public required IReadOnlyList<CandidateEntry> Candidates { get; init; }

    public required int TotalExpectedVotes { get; init; }

    public required int TurnoutVotes { get; init; }

    public int? CountedVotesFromApi { get; init; }

    public int? RemainingVotesFromApi { get; init; }

    public double? CountedRateFromApi { get; init; }

    public required DateTimeOffset ReceivedAt { get; init; }

    public string ReferenceTimeLabel { get; init; } = string.Empty;

    public IReadOnlyList<PreElectionHistoricalTurnoutEntry> HistoricalTurnoutHistory { get; init; } =
        Array.Empty<PreElectionHistoricalTurnoutEntry>();

    public IReadOnlyList<PreElectionHistoricalWinnerEntry> HistoricalWinnerHistory { get; init; } =
        Array.Empty<PreElectionHistoricalWinnerEntry>();

    public IReadOnlyList<TurnoutBoardSlotEntry> TurnoutBoardSlots { get; init; } =
        Array.Empty<TurnoutBoardSlotEntry>();

    public double? NationalTurnoutRateOverride { get; init; }

    public int CountedVotes => CountedVotesFromApi ?? Candidates.Sum(candidate => candidate.VoteCount);

    public int RemainingVotes => RemainingVotesFromApi ?? Math.Max(0, TotalExpectedVotes - CountedVotes);

    public double CountedRate => CountedRateFromApi ?? CalculateCountedRate();

    public double TurnoutRate => TotalExpectedVotes <= 0
        ? 0
        : Math.Round(TurnoutVotes * 100d / TotalExpectedVotes, 1, MidpointRounding.AwayFromZero);

    public double NationalTurnoutRate => NationalTurnoutRateOverride ?? TurnoutRate;

    private double CalculateCountedRate()
    {
        var denominator = TurnoutVotes > 0
            ? TurnoutVotes
            : TotalExpectedVotes;

        return denominator <= 0
            ? 0
            : Math.Round(CountedVotes * 100d / denominator, 1, MidpointRounding.AwayFromZero);
    }
}

public sealed record TurnoutBoardSlotEntry(
    int Slot,
    string Label,
    double TurnoutRate,
    bool IsNational = false,
    string RegionLabel = "",
    bool HasTurnoutData = true);
