import uuid
from sqlalchemy import Column, String, Text, Integer, ForeignKey, Boolean, Date, DateTime, Numeric, CheckConstraint, UniqueConstraint, Index
from sqlalchemy.orm import relationship
from sqlalchemy import Enum as SqlEnum
from utils.utils import Base, utc_now, ServiceType, InvoiceStatus, PaymentMethod

class Service(Base):
    __tablename__ = "services"
    
    id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    name = Column(String(200), nullable=False)
    description = Column(Text, nullable=True)
    service_type = Column(SqlEnum(ServiceType, name="servicetype_enum"), nullable=False)
    default_price = Column(Numeric(10, 2), nullable=False)
    default_duration_minutes = Column(Integer, nullable=True)
    department_id = Column(String(36), ForeignKey("departments.id", ondelete="SET NULL"), nullable=True, index=True)
    is_active = Column(Boolean, nullable=False, default=True)
    created_at = Column(DateTime(timezone=True), default=utc_now, nullable=False)
    updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now, nullable=False)
    
    department = relationship("Department", back_populates="services")
    invoice_line_items = relationship("Invoicelineitem", back_populates="service")


class Invoice(Base):
    __tablename__ = "invoices"
    
    id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    invoice_number = Column(String(50), nullable=False, unique=True, index=True)
    patient_id = Column(String(36), ForeignKey("patients.id", ondelete="RESTRICT"), nullable=False, index=True)
    appointment_id = Column(String(36), ForeignKey("appointments.id", ondelete="SET NULL"), nullable=True, index=True)
    invoice_date = Column(Date, nullable=False)
    due_date = Column(Date, nullable=True)
    subtotal = Column(Numeric(10, 2), nullable=False)
    tax_amount = Column(Numeric(10, 2), nullable=False, default=0)
    discount_amount = Column(Numeric(10, 2), nullable=False, default=0)
    total_amount = Column(Numeric(10, 2), nullable=False)
    amount_paid = Column(Numeric(10, 2), nullable=False, default=0)
    balance_due = Column(Numeric(10, 2), nullable=False)
    status = Column(SqlEnum(InvoiceStatus, name="invoicestatus_enum"), nullable=False)
    notes = Column(Text, nullable=True)
    created_by_user_id = Column(String(36), ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True)
    created_at = Column(DateTime(timezone=True), default=utc_now, nullable=False)
    updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now, nullable=False)
    
    patient = relationship("Patient", back_populates="invoices")
    appointment = relationship("Appointment", back_populates="invoices")
    created_by_user = relationship("User", foreign_keys=[created_by_user_id], back_populates="invoices_created")
    line_items = relationship("Invoicelineitem", back_populates="invoice", cascade="all, delete-orphan", passive_deletes=True)
    payments = relationship("Payment", back_populates="invoice")


class Invoicelineitem(Base):
    __tablename__ = "invoice_line_items"
    
    id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    invoice_id = Column(String(36), ForeignKey("invoices.id", ondelete="CASCADE"), nullable=False, index=True)
    service_id = Column(String(36), ForeignKey("services.id", ondelete="SET NULL"), nullable=True, index=True)
    description = Column(String(500), nullable=False)
    quantity = Column(Integer, nullable=False, default=1)
    unit_price = Column(Numeric(10, 2), nullable=False)
    line_total = Column(Numeric(10, 2), nullable=False)
    created_at = Column(DateTime(timezone=True), default=utc_now, nullable=False)
    updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now, nullable=False)
    
    invoice = relationship("Invoice", back_populates="line_items")
    service = relationship("Service", back_populates="invoice_line_items")
    
    __table_args__ = (
        CheckConstraint("quantity > 0", name="ck_invoice_line_items_quantity_pos"),
    )


class Payment(Base):
    __tablename__ = "payments"
    
    id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    invoice_id = Column(String(36), ForeignKey("invoices.id", ondelete="RESTRICT"), nullable=False, index=True)
    patient_id = Column(String(36), ForeignKey("patients.id", ondelete="RESTRICT"), nullable=False, index=True)
    payment_date = Column(DateTime(timezone=True), nullable=False)
    amount = Column(Numeric(10, 2), nullable=False)
    payment_method = Column(SqlEnum(PaymentMethod, name="paymentmethod_enum"), nullable=False)
    transaction_reference = Column(String(100), nullable=True)
    notes = Column(Text, nullable=True)
    processed_by_user_id = Column(String(36), ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True)
    created_at = Column(DateTime(timezone=True), default=utc_now, nullable=False)
    updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now, nullable=False)
    
    invoice = relationship("Invoice", back_populates="payments")
    patient = relationship("Patient", back_populates="payments")
    processed_by_user = relationship("User", foreign_keys=[processed_by_user_id], back_populates="payments_processed")
    
    __table_args__ = (
        CheckConstraint("amount > 0", name="ck_payments_amount_pos"),
    )