from __future__ import annotations

from dataclasses import dataclass, field
from datetime import date, datetime
from decimal import Decimal
from typing import Any


def _iso_now() -> str:
    return datetime.now().astimezone().isoformat(timespec="seconds")


MEMBERSHIP_STATUS_LABELS = {
    "application": "ANTRAG",
    "accepted_pending_payment": "ANGENOMMEN / ZAHLUNG OFFEN",
    "active": "AKTIV",
    "suspended_contribution": "RUHEND / BEITRAG",
    "resigned_end_of_year": "AUSTRITT ZUM JAHRESENDE",
    "honorary": "EHRENMITGLIED",
    "ended": "BEENDET",
}


@dataclass(slots=True)
class Member:
    member_id: str
    member_number: str
    first_name: str
    last_name: str
    email: str = ""
    phone: str = ""
    birth_date: str = ""
    street: str = ""
    address_addition: str = ""
    postal_code: str = ""
    city: str = ""
    country: str = "Deutschland"
    account_holder: str = ""
    iban: str = ""
    bic: str = ""
    mandate_reference: str = ""
    mandate_signed_at: str = ""
    mandate_active: bool = False
    mandate_revoked_at: str = ""
    status: str = "application"
    accepted_at: str = ""
    membership_started_at: str = ""
    payment_frequency: str = "annual"
    contribution_rule_id: str = "standard-2022"
    honorary: bool = False
    notes: str = ""
    created_at: str = field(default_factory=_iso_now)
    updated_at: str = field(default_factory=_iso_now)
    schema_version: int = 1

    @property
    def display_name(self) -> str:
        return " ".join(part for part in (self.first_name, self.last_name) if part).strip()

    def to_dict(self) -> dict[str, Any]:
        return {
            "schema_version": self.schema_version,
            "member_id": self.member_id,
            "member_number": self.member_number,
            "person": {
                "first_name": self.first_name,
                "last_name": self.last_name,
                "birth_date": self.birth_date,
                "email": self.email,
                "phone": self.phone,
            },
            "address": {
                "street": self.street,
                "addition": self.address_addition,
                "postal_code": self.postal_code,
                "city": self.city,
                "country": self.country,
            },
            "banking": {
                "account_holder": self.account_holder,
                "iban": self.iban,
                "bic": self.bic,
                "mandate_reference": self.mandate_reference,
                "mandate_signed_at": self.mandate_signed_at,
                "mandate_active": self.mandate_active,
                "mandate_revoked_at": self.mandate_revoked_at,
            },
            "membership": {
                "status": self.status,
                "accepted_at": self.accepted_at,
                "started_at": self.membership_started_at,
                "honorary": self.honorary,
            },
            "contribution_profile": {
                "rule_id": self.contribution_rule_id,
                "payment_frequency": self.payment_frequency,
            },
            "notes": self.notes,
            "created_at": self.created_at,
            "updated_at": self.updated_at,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> Member:
        person = data.get("person") or {}
        membership = data.get("membership") or {}
        contribution = data.get("contribution_profile") or {}
        address = data.get("address") or {}
        banking = data.get("banking") or {}
        return cls(
            schema_version=int(data.get("schema_version", 1)),
            member_id=str(data["member_id"]),
            member_number=str(data.get("member_number", "")),
            first_name=str(person.get("first_name", "")),
            last_name=str(person.get("last_name", "")),
            email=str(person.get("email", "")),
            phone=str(person.get("phone", "")),
            birth_date=str(person.get("birth_date", "")),
            street=str(address.get("street", "")),
            address_addition=str(address.get("addition", "")),
            postal_code=str(address.get("postal_code", "")),
            city=str(address.get("city", "")),
            country=str(address.get("country", "Deutschland")),
            account_holder=str(banking.get("account_holder", "")),
            iban=str(banking.get("iban", "")),
            bic=str(banking.get("bic", "")),
            mandate_reference=str(banking.get("mandate_reference", "")),
            mandate_signed_at=str(banking.get("mandate_signed_at", "")),
            mandate_active=bool(banking.get("mandate_active", False)),
            mandate_revoked_at=str(banking.get("mandate_revoked_at", "")),
            status=str(membership.get("status", "application")),
            accepted_at=str(membership.get("accepted_at", "")),
            membership_started_at=str(membership.get("started_at", "")),
            honorary=bool(membership.get("honorary", False)),
            contribution_rule_id=str(contribution.get("rule_id", "standard-2022")),
            payment_frequency=str(contribution.get("payment_frequency", "annual")),
            notes=str(data.get("notes", "")),
            created_at=str(data.get("created_at", _iso_now())),
            updated_at=str(data.get("updated_at", _iso_now())),
        )


@dataclass(slots=True)
class Event:
    event_id: str
    timestamp: str
    event_type: str
    summary: str
    actor_type: str = "system"
    actor_name: str = "CCMA"
    references: dict[str, str] = field(default_factory=dict)
    data: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        return {
            "schema_version": 1,
            "event_id": self.event_id,
            "timestamp": self.timestamp,
            "type": self.event_type,
            "actor": {"type": self.actor_type, "name": self.actor_name},
            "summary": self.summary,
            "references": self.references,
            "data": self.data,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> Event:
        actor = data.get("actor") or {}
        return cls(
            event_id=str(data["event_id"]),
            timestamp=str(data["timestamp"]),
            event_type=str(data.get("type", "unknown")),
            summary=str(data.get("summary", "")),
            actor_type=str(actor.get("type", "system")),
            actor_name=str(actor.get("name", "CCMA")),
            references=dict(data.get("references") or {}),
            data=dict(data.get("data") or {}),
        )


@dataclass(slots=True)
class ContributionData:
    claims: list[dict[str, Any]] = field(default_factory=list)
    payments: list[dict[str, Any]] = field(default_factory=list)
    allocations: list[dict[str, Any]] = field(default_factory=list)
    reminders: list[dict[str, Any]] = field(default_factory=list)
    schema_version: int = 1

    def to_dict(self) -> dict[str, Any]:
        return {
            "schema_version": self.schema_version,
            "claims": self.claims,
            "payments": self.payments,
            "allocations": self.allocations,
            "reminders": self.reminders,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> ContributionData:
        return cls(
            schema_version=int(data.get("schema_version", 1)),
            claims=list(data.get("claims") or []),
            payments=list(data.get("payments") or []),
            allocations=list(data.get("allocations") or []),
            reminders=list(data.get("reminders") or []),
        )


@dataclass(frozen=True, slots=True)
class HousekeeperFinding:
    severity: str
    member_id: str
    code: str
    title: str
    detail: str
    due_date: date | None = None
    key: str = ""


def money(value: str | int | float | Decimal) -> Decimal:
    return Decimal(str(value)).quantize(Decimal("0.01"))
