from __future__ import annotations

import uuid
from datetime import datetime

from sqlalchemy import (
    DateTime,
    ForeignKey,
    ForeignKeyConstraint,
    Index,
    String,
    UniqueConstraint,
    func,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.db.base_class import Base


class OrganizationUnit(Base):
    __tablename__ = "organization_units"
    __table_args__ = (
        UniqueConstraint(
            "tenant_id",
            "id",
            name="uq_organization_units_tenant_id",
        ),
        UniqueConstraint(
            "tenant_id",
            "unit_code",
            name="uq_organization_units_tenant_code",
        ),
        ForeignKeyConstraint(
            ["tenant_id", "parent_id"],
            ["organization_units.tenant_id", "organization_units.id"],
            name="fk_organization_units_tenant_parent",
            ondelete="RESTRICT",
        ),
        Index("ix_organization_units_tenant_name", "tenant_id", "name"),
    )

    id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    tenant_id: Mapped[str] = mapped_column(
        ForeignKey("tenants.tenant_id", ondelete="RESTRICT"),
        nullable=False,
        server_default="default",
    )
    unit_code: Mapped[str] = mapped_column(String(50), index=True)
    name: Mapped[str] = mapped_column(String(100), index=True)
    unit_type: Mapped[str] = mapped_column(String(30), default="department", index=True)
    parent_id: Mapped[str | None] = mapped_column(nullable=True, index=True)
    cost_center: Mapped[str | None] = mapped_column(String(50), nullable=True)
    location: Mapped[str | None] = mapped_column(String(100), nullable=True)
    manager_name: Mapped[str | None] = mapped_column(String(100), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
    )

    parent = relationship(
        "OrganizationUnit",
        remote_side=[tenant_id, id],
        foreign_keys=[tenant_id, parent_id],
        back_populates="children",
    )
    children = relationship(
        "OrganizationUnit",
        foreign_keys=[tenant_id, parent_id],
        back_populates="parent",
    )
    employees = relationship(
        "Employee",
        primaryjoin=(
            "and_(OrganizationUnit.tenant_id == Employee.tenant_id, "
            "OrganizationUnit.id == foreign(Employee.organization_unit_id))"
        ),
        foreign_keys="[Employee.organization_unit_id]",
        back_populates="organization_unit",
        overlaps="manager,reports",
    )
