from datetime import datetime
from typing import Optional
from decimal import Decimal
from geoalchemy2 import Geography
from sqlalchemy import DateTime, Numeric, SmallInteger, String, Text
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship
from src.database.base import BaseModel
from src.core.constants import AccountStatus, SubscriptionPlan


class Account(BaseModel):
    __tablename__ = "accounts"

    organization_name: Mapped[str] = mapped_column(String(255), nullable=False)
    subdomain: Mapped[str] = mapped_column(String(100), nullable=False, unique=True, index=True)
    cemetery_type: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    contact_email: Mapped[str] = mapped_column(String(255), nullable=False)
    contact_phone: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    address: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    status: Mapped[str] = mapped_column(
        String(50), nullable=False, default=AccountStatus.NEW.value, index=True
    )
    onboarding_completed_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    plan: Mapped[str] = mapped_column(
        String(50), nullable=False, default=SubscriptionPlan.STARTER.value
    )
    config_json: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True, default=dict)
    established_year: Mapped[Optional[int]] = mapped_column(SmallInteger, nullable=True)

    # Signup management fields (migration 0005)
    credentials_sent_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    account_manager: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    size: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    signup_source: Mapped[str] = mapped_column(
        String(20), nullable=False, default="marketing", index=True
    )
    activated_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    feature_flags: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True, default=dict)

    # Temporary plain-text password stored until first login / manual reset
    temp_password: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)

    # Stripe
    stripe_customer_id: Mapped[Optional[str]] = mapped_column(
        String(255), nullable=True, unique=True, index=True
    )

    # ── Cemetery map geometry (INDL-49 / shared foundation for INDL-41) ──────────
    boundary: Mapped[Optional[object]] = mapped_column(
        Geography(geometry_type="POLYGON", srid=4326), nullable=True
    )
    centroid: Mapped[Optional[object]] = mapped_column(
        Geography(geometry_type="POINT", srid=4326), nullable=True
    )
    map_mode: Mapped[str] = mapped_column(
        String(20), nullable=False, default="image", server_default="image"
    )
    total_area_m2: Mapped[Optional[Decimal]] = mapped_column(
        Numeric(12, 2), nullable=True
    )

    # ── Last-searched address cache (INDL-49, AC-19) ────────────────────────────
    map_search_lat: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 7), nullable=True)
    map_search_lng: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 7), nullable=True)
    map_search_address: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)

    # Relationships
    users: Mapped[list] = relationship("User", back_populates="tenant", lazy="noload")
    branding: Mapped[Optional[object]] = relationship(
        "BrandingConfig", back_populates="account", uselist=False, lazy="noload"
    )
    subscriptions: Mapped[list] = relationship(
        "Subscription", back_populates="account", lazy="noload"
    )

    def __repr__(self) -> str:
        return f"<Account {self.subdomain}>"
