"""
Journal Entry and Journal Line models for General Ledger.
"""
from sqlalchemy import Column, Integer, String, DateTime, Numeric, Text, Enum, ForeignKey, JSON, Index
from sqlalchemy.orm import relationship
from datetime import datetime
import enum
from ...shared.config.database import Base


class JournalEntryStatus(str, enum.Enum):
    """Status of a journal entry."""
    draft = 'draft'
    posted = 'posted'
    reversed = 'reversed'


class JournalEntry(Base):
    """Journal Entry for recording financial transactions."""
    __tablename__ = 'journal_entries'
    
    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    
    # Entry identification
    entry_number = Column(String(50), unique=True, nullable=False, index=True)
    entry_date = Column(DateTime, nullable=False, index=True)
    status = Column(Enum(JournalEntryStatus), default=JournalEntryStatus.draft, nullable=False, index=True)
    
    # Period and reference
    fiscal_period_id = Column(Integer, ForeignKey('fiscal_periods.id'), nullable=False, index=True)
    reference_type = Column(String(50), nullable=True)  # 'booking', 'invoice', 'payment', 'manual'
    reference_id = Column(Integer, nullable=True, index=True)  # ID of the referenced entity
    
    # Entry details
    description = Column(Text, nullable=False)
    notes = Column(Text, nullable=True)
    
    # User tracking
    created_by = Column(Integer, ForeignKey('users.id'), nullable=False)
    posted_by = Column(Integer, ForeignKey('users.id'), nullable=True)
    posted_at = Column(DateTime, nullable=True)
    
    # Reversal tracking
    reversed_by = Column(Integer, ForeignKey('users.id'), nullable=True)
    reversed_at = Column(DateTime, nullable=True)
    reversal_reason = Column(Text, nullable=True)
    original_entry_id = Column(Integer, ForeignKey('journal_entries.id'), nullable=True)
    
    # Additional metadata
    entry_metadata = Column(JSON, nullable=True)
    
    # Timestamps
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    
    # Relationships
    fiscal_period = relationship('FiscalPeriod', back_populates='journal_entries')
    journal_lines = relationship('JournalLine', back_populates='journal_entry', cascade='all, delete-orphan')
    creator = relationship('User', foreign_keys=[created_by])
    poster = relationship('User', foreign_keys=[posted_by])
    reverser = relationship('User', foreign_keys=[reversed_by])
    original_entry = relationship('JournalEntry', remote_side=[id], backref='reversals')
    
    # Indexes
    __table_args__ = (
        Index('idx_journal_entry_date', 'entry_date', 'status'),
        Index('idx_journal_entry_reference', 'reference_type', 'reference_id'),
        Index('idx_journal_entry_period', 'fiscal_period_id', 'status'),
    )


class JournalLine(Base):
    """Journal Line for individual account postings within a journal entry."""
    __tablename__ = 'journal_lines'
    
    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    
    # Entry reference
    journal_entry_id = Column(Integer, ForeignKey('journal_entries.id'), nullable=False, index=True)
    line_number = Column(Integer, nullable=False)  # Line sequence within entry
    
    # Account reference
    account_id = Column(Integer, ForeignKey('chart_of_accounts.id'), nullable=False, index=True)
    
    # Amounts
    debit_amount = Column(Numeric(10, 2), nullable=True, default=0.0)
    credit_amount = Column(Numeric(10, 2), nullable=True, default=0.0)
    
    # Line details
    description = Column(Text, nullable=True)
    
    # Timestamps
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    
    # Relationships
    journal_entry = relationship('JournalEntry', back_populates='journal_lines')
    account = relationship('ChartOfAccounts', back_populates='journal_lines')
    
    # Indexes
    __table_args__ = (
        Index('idx_journal_line_account', 'account_id', 'created_at'),
        Index('idx_journal_line_entry', 'journal_entry_id', 'line_number'),
    )

