"""
Billing, Invoice, and Usage Models
"""
from datetime import datetime
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, JSON, Enum as SQLEnum, Boolean, Numeric
from sqlalchemy.orm import relationship
import enum

from app.models.base import Base, TimestampMixin


class InvoiceStatus(enum.Enum):
    DRAFT = "draft"
    PENDING = "pending"
    PAID = "paid"
    OVERDUE = "overdue"
    CANCELLED = "cancelled"
    REFUNDED = "refunded"


class PaymentStatus(enum.Enum):
    PENDING = "pending"
    SUCCESS = "success"
    FAILED = "failed"
    REFUNDED = "refunded"


class PaymentMethod(enum.Enum):
    RAZORPAY = "razorpay"
    STRIPE = "stripe"
    BANK_TRANSFER = "bank_transfer"
    UPI = "upi"
    CARD = "card"
    WALLET = "wallet"


class UsageType(enum.Enum):
    CHAT_MESSAGE = "chat_message"
    CHAT_TOKEN = "chat_token"
    VISION_REQUEST = "vision_request"
    ANALYTICS_REPORT = "analytics_report"
    API_CALL = "api_call"
    WHATSAPP_MESSAGE = "whatsapp_message"


class Invoice(Base, TimestampMixin):
    """
    Invoice Model
    """
    __tablename__ = "invoices"

    id = Column(Integer, primary_key=True, index=True)
    client_id = Column(Integer, ForeignKey("clients.id"), nullable=False, index=True)
    subscription_id = Column(Integer, ForeignKey("subscriptions.id"), nullable=True)

    # Invoice Details
    invoice_number = Column(String(50), unique=True, nullable=False, index=True)
    status = Column(SQLEnum(InvoiceStatus), default=InvoiceStatus.DRAFT)

    # Billing Period
    billing_period_start = Column(DateTime, nullable=False)
    billing_period_end = Column(DateTime, nullable=False)

    # Amounts
    subtotal = Column(Numeric(10, 2), default=0)
    tax_percentage = Column(Numeric(5, 2), default=18)  # GST 18%
    tax_amount = Column(Numeric(10, 2), default=0)
    discount_amount = Column(Numeric(10, 2), default=0)
    total_amount = Column(Numeric(10, 2), nullable=False)
    currency = Column(String(3), default="INR")

    # Line Items
    line_items = Column(JSON, default=[])
    # Example: [{"description": "Starter Plan - Monthly", "quantity": 1, "unit_price": 5000, "amount": 5000}]

    # Dates
    issue_date = Column(DateTime, default=datetime.utcnow)
    due_date = Column(DateTime, nullable=False)
    paid_at = Column(DateTime, nullable=True)

    # Payment Info
    payment_method = Column(SQLEnum(PaymentMethod), nullable=True)
    transaction_id = Column(String(100), nullable=True)

    # Notes
    notes = Column(Text, nullable=True)
    internal_notes = Column(Text, nullable=True)

    # PDF
    pdf_url = Column(String(500), nullable=True)

    # Relationships
    client = relationship("Client", back_populates="invoices")
    payments = relationship("Payment", back_populates="invoice", cascade="all, delete-orphan")

    @staticmethod
    def generate_invoice_number():
        """Generate unique invoice number"""
        from datetime import datetime
        import random
        return f"INV-{datetime.now().strftime('%Y%m')}-{random.randint(1000, 9999)}"

    def __repr__(self):
        return f"<Invoice(id={self.id}, invoice_number='{self.invoice_number}')>"


class Payment(Base, TimestampMixin):
    """
    Payment Transaction Model
    """
    __tablename__ = "payments"

    id = Column(Integer, primary_key=True, index=True)
    invoice_id = Column(Integer, ForeignKey("invoices.id"), nullable=False)

    # Payment Details
    amount = Column(Numeric(10, 2), nullable=False)
    currency = Column(String(3), default="INR")
    status = Column(SQLEnum(PaymentStatus), default=PaymentStatus.PENDING)
    method = Column(SQLEnum(PaymentMethod), nullable=False)

    # Gateway Details
    gateway_payment_id = Column(String(100), nullable=True)  # Razorpay/Stripe payment ID
    gateway_order_id = Column(String(100), nullable=True)
    gateway_signature = Column(String(255), nullable=True)
    gateway_response = Column(JSON, nullable=True)

    # Dates
    initiated_at = Column(DateTime, default=datetime.utcnow)
    completed_at = Column(DateTime, nullable=True)

    # Refund
    refund_amount = Column(Numeric(10, 2), default=0)
    refund_reason = Column(Text, nullable=True)
    refunded_at = Column(DateTime, nullable=True)

    # Error Handling
    error_code = Column(String(50), nullable=True)
    error_message = Column(Text, nullable=True)

    # Relationships
    invoice = relationship("Invoice", back_populates="payments")

    def __repr__(self):
        return f"<Payment(id={self.id}, amount={self.amount})>"


class UsageLog(Base, TimestampMixin):
    """
    Usage Tracking Model - For metering and billing
    """
    __tablename__ = "usage_logs"

    id = Column(Integer, primary_key=True, index=True)
    client_id = Column(Integer, ForeignKey("clients.id"), nullable=False, index=True)

    # Usage Details
    usage_type = Column(SQLEnum(UsageType), nullable=False)
    quantity = Column(Integer, default=1)

    # Context
    conversation_id = Column(Integer, ForeignKey("conversations.id"), nullable=True)
    api_key_id = Column(Integer, ForeignKey("client_api_keys.id"), nullable=True)

    # Model Details (for AI usage)
    model = Column(String(50), nullable=True)
    input_tokens = Column(Integer, default=0)
    output_tokens = Column(Integer, default=0)
    total_tokens = Column(Integer, default=0)

    # Cost Calculation
    unit_cost = Column(Numeric(10, 6), default=0)  # Cost per unit
    total_cost = Column(Numeric(10, 4), default=0)

    # Extra Data
    extra_data = Column(JSON, nullable=True)

    # Billing Period
    billing_period = Column(String(7), nullable=True)  # e.g., "2026-09"

    # Relationships
    client = relationship("Client", back_populates="usage_logs")

    def __repr__(self):
        return f"<UsageLog(id={self.id}, type='{self.usage_type.value}')>"


class UsageSummary(Base, TimestampMixin):
    """
    Daily/Monthly Usage Summary for quick lookups
    """
    __tablename__ = "usage_summaries"

    id = Column(Integer, primary_key=True, index=True)
    client_id = Column(Integer, ForeignKey("clients.id"), nullable=False, index=True)

    # Period
    period_type = Column(String(10), nullable=False)  # "daily", "monthly"
    period_date = Column(String(10), nullable=False)  # "2026-09-21" or "2026-09"

    # Counts
    total_messages = Column(Integer, default=0)
    total_conversations = Column(Integer, default=0)
    total_tokens = Column(Integer, default=0)
    total_vision_requests = Column(Integer, default=0)
    total_api_calls = Column(Integer, default=0)

    # Cost
    total_cost = Column(Numeric(10, 4), default=0)

    # Unique constraint
    __table_args__ = (
        # Ensure unique combination of client_id, period_type, and period_date
    )

    def __repr__(self):
        return f"<UsageSummary(client_id={self.client_id}, period='{self.period_date}')>"
