"""Companies (the legal/economic entity) and Securities (1:N listed lines)."""
from __future__ import annotations

from datetime import date
from typing import TYPE_CHECKING, Optional

from sqlalchemy import Boolean, Date, ForeignKey, String, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.models.base import Base, TimestampMixin, uuid_pk

if TYPE_CHECKING:  # pragma: no cover - import cycle guard
    # SQLAlchemy resolves these relationship targets from its own registry at mapper-configuration
    # time, so they are never imported at runtime; this block exists so static analysis can see
    # that the string annotations below refer to real classes.
    from app.models.reference import Country, Exchange, Industry, Sector


class Company(Base, TimestampMixin):
    __tablename__ = "companies"

    id: Mapped[str] = uuid_pk()
    legal_name: Mapped[str] = mapped_column(String(256), index=True)
    display_name: Mapped[str] = mapped_column(String(128), index=True)
    country_id: Mapped[str] = mapped_column(ForeignKey("countries.id"), index=True)
    sector_id: Mapped[str] = mapped_column(ForeignKey("sectors.id"), index=True)
    industry_id: Mapped[str] = mapped_column(ForeignKey("industries.id"), index=True)
    website: Mapped[Optional[str]] = mapped_column(String(256), nullable=True)
    description: Mapped[Optional[str]] = mapped_column(nullable=True)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True)

    country: Mapped["Country"] = relationship()
    sector: Mapped["Sector"] = relationship()
    industry: Mapped["Industry"] = relationship()
    securities: Mapped[list["Security"]] = relationship(back_populates="company")


class Security(Base, TimestampMixin):
    """A listed line for a company — a company can have multiple (home listing + ADR, dual
    listing, secondary listing)."""

    __tablename__ = "securities"
    __table_args__ = (UniqueConstraint("ticker", "exchange_id", name="uq_security_ticker_exchange"),)

    id: Mapped[str] = uuid_pk()
    company_id: Mapped[str] = mapped_column(ForeignKey("companies.id"), index=True)
    exchange_id: Mapped[str] = mapped_column(ForeignKey("exchanges.id"), index=True)
    ticker: Mapped[str] = mapped_column(String(32), index=True)
    isin: Mapped[Optional[str]] = mapped_column(String(12), nullable=True, index=True)
    cusip: Mapped[Optional[str]] = mapped_column(String(9), nullable=True)
    security_type: Mapped[str] = mapped_column(String(16), default="COMMON")  # COMMON | ADR | PREFERRED | ETF
    currency: Mapped[str] = mapped_column(String(3))
    is_primary_listing: Mapped[bool] = mapped_column(Boolean, default=True)
    listing_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
    delisting_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
    status: Mapped[str] = mapped_column(String(16), default="ACTIVE")  # ACTIVE | DELISTED | SUSPENDED
    discovery_status: Mapped[Optional[str]] = mapped_column(String(24), nullable=True)
    # DISCOVERED | UNDER_REVIEW | QUALIFIED | WATCHLIST | INVESTABLE | REJECTED (spec §6)

    company: Mapped["Company"] = relationship(back_populates="securities")
    exchange: Mapped["Exchange"] = relationship()
