from sqlalchemy import (
    Boolean,
    Integer,
    ForeignKey,
    Float,
    Text,
    JSON,
    String,
    DateTime,
)
from sqlalchemy.orm import relationship, Session, Mapped, mapped_column
from typing import Dict, Optional, TYPE_CHECKING, Any
import json
from sqlalchemy.sql import func
from src.apps.base.models.base import Base
from src.core.utils.enums import AuthorizationRecordTypes
from sqlalchemy.ext.hybrid import hybrid_property
from datetime import datetime

if TYPE_CHECKING:
    from src.apps.payment_requests.models.payment_request import PaymentRequest
    from src.apps.users.models.user import User


class PaymentRequestAuthorizations(Base):
    """
    Payment Request Authorization Model: ORM class for Payment Request Authorization Entity
    """

    __tablename__ = "payment_requests_authorizations"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True, autoincrement=True)
    authorization_id: Mapped[Optional[str]] = mapped_column(String(50), index=True, unique=True, nullable=True)
    authorization_literal: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    authorization_date: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    authorization_type: Mapped[str] = mapped_column(String, default=AuthorizationRecordTypes.CHECKBOX)
    authorization_value: Mapped[Optional[str]] = mapped_column(Text, default=None)
    auth_metadata: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    is_verified: Mapped[bool] = mapped_column(Boolean, default=False)
    signing_name: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    ip_address: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)

    payment_request_id: Mapped[int] = mapped_column(Integer, ForeignKey("payment_requests.id"))
    payment_request: Mapped["PaymentRequest"] = relationship(
        "PaymentRequest", back_populates="payment_request_authorizations"
    )

    customer_id: Mapped[int] = mapped_column(Integer, ForeignKey("customers.id"))
    customer: Mapped[Any] = relationship("Customer", back_populates="payment_request_authorizations")

    payer_id: Mapped[int] = mapped_column(Integer, ForeignKey("customer_contacts.id"))
    payer: Mapped[Any] = relationship(
        "CustomerContact", back_populates="payment_request_authorizations"
    )

    merchant_signer_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"))
    merchant_signer: Mapped["User"] = relationship(
        "User", foreign_keys=[merchant_signer_id], uselist=False
    )

    # TODO: Uncomment when Contract model is created
    # contract_id: Mapped[int] = mapped_column(Integer, ForeignKey("contracts.id"))
    # contract: Mapped[Any] = relationship("Contract", back_populates="payment_request_authorizations")

    merchant_id: Mapped[int] = mapped_column(Integer, ForeignKey("merchants.id"))
    merchant: Mapped[Any] = relationship("Merchant", back_populates="payment_request_authorizations")

    created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
    updated_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True, onupdate=func.now())
    deleted_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)

    @hybrid_property
    def additional_info(self) -> Dict:
        result: Dict = dict()
        try:
            if isinstance(self.auth_metadata, str):
                result = json.loads(self.auth_metadata)
            elif isinstance(self.auth_metadata, dict):
                result = self.auth_metadata
        except:
            pass
        return result
