"""
Pydantic Models for Ticket System & Klippekort Module
======================================================

Alle models repræsenterer data fra tticket_* tabeller.
Modulet er isoleret og har ingen afhængigheder til core Hub-models.
"""

from datetime import date, datetime
from decimal import Decimal
from typing import List, Optional
from pydantic import BaseModel, Field, field_validator
from enum import Enum


# ============================================================================
# ENUMS
# ============================================================================

class TicketStatus(str, Enum):
    """Ticket status workflow"""
    OPEN = "open"
    IN_PROGRESS = "in_progress"
    WAITING_CUSTOMER = "waiting_customer"
    WAITING_INTERNAL = "waiting_internal"
    RESOLVED = "resolved"
    CLOSED = "closed"


class TicketPriority(str, Enum):
    """Ticket prioritet"""
    LOW = "low"
    NORMAL = "normal"
    HIGH = "high"
    URGENT = "urgent"


class TicketSource(str, Enum):
    """Hvor ticket blev oprettet fra"""
    EMAIL = "email"
    PORTAL = "portal"
    PHONE = "phone"
    MANUAL = "manual"
    API = "api"


class WorkType(str, Enum):
    """Type af arbejde"""
    SUPPORT = "support"
    DEVELOPMENT = "development"
    TROUBLESHOOTING = "troubleshooting"
    ON_SITE = "on_site"
    MEETING = "meeting"
    OTHER = "other"


class BillingMethod(str, Enum):
    """Afregningsmetode"""
    PREPAID_CARD = "prepaid_card"
    FIXED_PRICE = "fixed_price"
    INVOICE = "invoice"
    INTERNAL = "internal"
    WARRANTY = "warranty"
    UNKNOWN = "unknown"


class WorklogStatus(str, Enum):
    """Worklog status"""
    DRAFT = "draft"
    BILLABLE = "billable"
    BILLED = "billed"
    NON_BILLABLE = "non_billable"


class PrepaidCardStatus(str, Enum):
    """Klippekort status"""
    ACTIVE = "active"
    DEPLETED = "depleted"
    EXPIRED = "expired"
    CANCELLED = "cancelled"


class TransactionType(str, Enum):
    """Klippekort transaction type"""
    PURCHASE = "purchase"
    TOP_UP = "top_up"
    USAGE = "usage"
    REFUND = "refund"
    EXPIRATION = "expiration"
    CANCELLATION = "cancellation"


class TicketType(str, Enum):
    """Ticket kategorisering"""
    INCIDENT = "incident"      # Fejl der skal fixes (Høj urgens)
    REQUEST = "request"        # Bestilling / Ønske (Planlægges)
    PROBLEM = "problem"        # Root cause (Fejlfinding)
    PROJECT = "project"        # Større projektarbejde


# ============================================================================
# TICKET MODELS
# ============================================================================

class TTicketBase(BaseModel):
    """Base model for ticket"""
    subject: str = Field(..., min_length=1, max_length=500)
    description: Optional[str] = None
    status: TicketStatus = Field(default=TicketStatus.OPEN)
    priority: TicketPriority = Field(default=TicketPriority.NORMAL)
    ticket_type: TicketType = Field(default=TicketType.INCIDENT, description="Type af sag")
    internal_note: Optional[str] = Field(default=None, description="Intern note der vises prominent til medarbejdere")
    category: Optional[str] = Field(None, max_length=100)
    customer_id: Optional[int] = Field(None, description="Reference til customers.id")
    contact_id: Optional[int] = Field(None, description="Reference til contacts.id")
    assigned_to_user_id: Optional[int] = Field(None, description="Reference til users.user_id")
    source: TicketSource = Field(default=TicketSource.MANUAL)
    tags: Optional[List[str]] = Field(default_factory=list)
    custom_fields: Optional[dict] = Field(default_factory=dict)


class TTicketCreate(TTicketBase):
    """Model for creating a ticket"""
    ticket_number: Optional[str] = Field(None, description="Auto-generated hvis ikke angivet")
    created_by_user_id: Optional[int] = Field(None, description="User der opretter ticket")


class TTicketUpdate(BaseModel):
    """Model for updating a ticket (partial updates)"""
    subject: Optional[str] = Field(None, min_length=1, max_length=500)
    description: Optional[str] = None
    status: Optional[TicketStatus] = None
    priority: Optional[TicketPriority] = None
    category: Optional[str] = Field(None, max_length=100)
    customer_id: Optional[int] = None
    contact_id: Optional[int] = None
    assigned_to_user_id: Optional[int] = None
    tags: Optional[List[str]] = None
    custom_fields: Optional[dict] = None


class TTicket(TTicketBase):
    """Full ticket model with DB fields"""
    id: int
    ticket_number: str
    created_by_user_id: Optional[int] = None
    created_at: datetime
    updated_at: Optional[datetime] = None
    first_response_at: Optional[datetime] = None
    resolved_at: Optional[datetime] = None
    closed_at: Optional[datetime] = None
    
    class Config:
        from_attributes = True


class TTicketWithStats(TTicket):
    """Ticket med statistik (fra view)"""
    comment_count: Optional[int] = 0
    attachment_count: Optional[int] = 0
    pending_hours: Optional[Decimal] = None
    billed_hours: Optional[Decimal] = None
    last_comment_at: Optional[datetime] = None
    age_hours: Optional[float] = None
    
    class Config:
        from_attributes = True


# ============================================================================
# COMMENT MODELS
# ============================================================================

class TTicketCommentBase(BaseModel):
    """Base model for comment"""
    comment_text: str = Field(..., min_length=1)
    is_internal: bool = Field(default=False, description="Intern note (ikke kunde-synlig)")


class TTicketCommentCreate(TTicketCommentBase):
    """Model for creating a comment"""
    ticket_id: int = Field(..., gt=0)
    user_id: Optional[int] = Field(None, description="User der opretter kommentar")


class TTicketComment(TTicketCommentBase):
    """Full comment model with DB fields"""
    id: int
    ticket_id: int
    user_id: Optional[int] = None
    created_at: datetime
    updated_at: Optional[datetime] = None
    
    class Config:
        from_attributes = True


# ============================================================================
# ATTACHMENT MODELS
# ============================================================================

class TTicketAttachmentBase(BaseModel):
    """Base model for attachment"""
    file_name: str = Field(..., min_length=1, max_length=255)
    file_path: str = Field(..., min_length=1, max_length=500)
    file_size: Optional[int] = Field(None, ge=0)
    mime_type: Optional[str] = Field(None, max_length=100)


class TTicketAttachmentCreate(TTicketAttachmentBase):
    """Model for creating an attachment"""
    ticket_id: int = Field(..., gt=0)
    uploaded_by_user_id: Optional[int] = None


class TTicketAttachment(TTicketAttachmentBase):
    """Full attachment model with DB fields"""
    id: int
    ticket_id: int
    uploaded_by_user_id: Optional[int] = None
    created_at: datetime
    
    class Config:
        from_attributes = True


# ============================================================================
# WORKLOG MODELS
# ============================================================================

class TTicketWorklogBase(BaseModel):
    """Base model for worklog entry"""
    work_date: date = Field(..., description="Dato arbejdet blev udført")
    hours: Decimal = Field(..., gt=0, le=24, description="Timer brugt")
    work_type: WorkType = Field(default=WorkType.SUPPORT)
    description: Optional[str] = None
    billing_method: BillingMethod = Field(default=BillingMethod.INVOICE)
    is_internal: bool = Field(default=False, description="Skjul for kunde (vises ikke på faktura/portal)")
    
    @field_validator('hours')
    @classmethod
    def validate_hours(cls, v):
        """Validate hours is reasonable (max 24 hours per day)"""
        if v <= 0:
            raise ValueError('Hours must be greater than 0')
        if v > 24:
            raise ValueError('Hours cannot exceed 24 per entry')
        return v


class TTicketWorklogCreate(TTicketWorklogBase):
    """Model for creating a worklog entry"""
    ticket_id: int = Field(..., gt=0)
    user_id: Optional[int] = Field(None, description="User der opretter worklog")
    prepaid_card_id: Optional[int] = Field(None, description="Klippekort ID hvis billing_method=prepaid_card")


class TTicketWorklogUpdate(BaseModel):
    """Model for updating a worklog entry (partial updates)"""
    work_date: Optional[date] = None
    hours: Optional[Decimal] = Field(None, gt=0, le=24)
    work_type: Optional[WorkType] = None
    description: Optional[str] = None
    billing_method: Optional[BillingMethod] = None
    status: Optional[WorklogStatus] = None
    prepaid_card_id: Optional[int] = None
    is_internal: Optional[bool] = None


class TTicketWorklog(TTicketWorklogBase):
    """Full worklog model with DB fields"""
    id: int
    ticket_id: int
    user_id: Optional[int] = None
    status: WorklogStatus = Field(default=WorklogStatus.DRAFT)
    prepaid_card_id: Optional[int] = None
    created_at: datetime
    updated_at: Optional[datetime] = None
    billed_at: Optional[datetime] = None
    
    class Config:
        from_attributes = True


class TTicketWorklogWithDetails(TTicketWorklog):
    """Worklog med ticket detaljer (til review UI)"""
    ticket_number: Optional[str] = None
    ticket_subject: Optional[str] = None
    customer_id: Optional[int] = None
    ticket_status: Optional[str] = None
    has_sufficient_balance: Optional[bool] = True
    
    class Config:
        from_attributes = True


# ============================================================================
# PREPAID CARD (KLIPPEKORT) MODELS
# ============================================================================

class TPrepaidCardBase(BaseModel):
    """Base model for prepaid card"""
    customer_id: int = Field(..., gt=0, description="Reference til customers.id")
    purchased_hours: Decimal = Field(..., gt=0, description="Timer købt")
    price_per_hour: Decimal = Field(..., gt=0, description="DKK pr. time")
    total_amount: Decimal = Field(..., gt=0, description="Total pris DKK")
    expires_at: Optional[datetime] = Field(None, description="Udløbsdato (NULL = ingen udløb)")
    notes: Optional[str] = None
    
    @field_validator('total_amount')
    @classmethod
    def validate_total(cls, v, info):
        """Validate that total_amount matches purchased_hours * price_per_hour"""
        # Note: This validator runs after all fields are set in Pydantic v2
        # If we need cross-field validation, use model_validator instead
        if v <= 0:
            raise ValueError('Total amount must be greater than 0')
        return v


class TPrepaidCardCreate(TPrepaidCardBase):
    """Model for creating a prepaid card"""
    card_number: Optional[str] = Field(None, description="Auto-generated hvis ikke angivet")
    created_by_user_id: Optional[int] = Field(None, description="User der opretter kort")
    economic_invoice_number: Optional[str] = Field(None, max_length=50)
    economic_product_number: Optional[str] = Field(None, max_length=50)


class TPrepaidCardUpdate(BaseModel):
    """Model for updating a prepaid card (partial updates)"""
    status: Optional[PrepaidCardStatus] = None
    expires_at: Optional[datetime] = None
    notes: Optional[str] = None
    economic_invoice_number: Optional[str] = Field(None, max_length=50)
    economic_product_number: Optional[str] = Field(None, max_length=50)


class TPrepaidCard(TPrepaidCardBase):
    """Full prepaid card model with DB fields"""
    id: int
    card_number: str
    used_hours: Decimal = Field(default=Decimal('0'))
    remaining_hours: Decimal  # Generated column
    status: PrepaidCardStatus = Field(default=PrepaidCardStatus.ACTIVE)
    purchased_at: datetime
    economic_invoice_number: Optional[str] = None
    economic_product_number: Optional[str] = None
    created_by_user_id: Optional[int] = None
    created_at: datetime
    updated_at: Optional[datetime] = None
    
    class Config:
        from_attributes = True


class TPrepaidCardWithStats(TPrepaidCard):
    """Prepaid card med statistik (fra view)"""
    usage_count: Optional[int] = 0
    total_hours_used: Optional[Decimal] = None
    billed_usage_count: Optional[int] = 0
    
    class Config:
        from_attributes = True


# ============================================================================
# PREPAID TRANSACTION MODELS
# ============================================================================

class TPrepaidTransactionBase(BaseModel):
    """Base model for prepaid transaction"""
    transaction_type: TransactionType
    hours: Decimal = Field(..., description="Timer (positiv=tilføj, negativ=træk)")
    description: Optional[str] = None


class TPrepaidTransactionCreate(TPrepaidTransactionBase):
    """Model for creating a transaction"""
    card_id: int = Field(..., gt=0)
    worklog_id: Optional[int] = Field(None, description="Reference til worklog (NULL for køb/top-up)")
    balance_after: Decimal = Field(..., ge=0, description="Saldo efter transaction")
    created_by_user_id: Optional[int] = None


class TPrepaidTransaction(TPrepaidTransactionBase):
    """Full transaction model with DB fields"""
    id: int
    card_id: int
    worklog_id: Optional[int] = None
    balance_after: Decimal
    created_at: datetime
    created_by_user_id: Optional[int] = None
    
    class Config:
        from_attributes = True


# ============================================================================
# EMAIL INTEGRATION MODELS
# ============================================================================

class TTicketEmailLogBase(BaseModel):
    """Base model for email log"""
    action: str = Field(..., max_length=50)


class TTicketEmailLogCreate(TTicketEmailLogBase):
    """Model for creating an email log entry"""
    ticket_id: Optional[int] = None
    email_id: Optional[int] = Field(None, description="Reference til email_messages.id")
    email_message_id: Optional[str] = Field(None, max_length=500, description="Email Message-ID header")


class TTicketEmailLog(TTicketEmailLogBase):
    """Full email log model with DB fields"""
    id: int
    ticket_id: Optional[int] = None
    email_id: Optional[int] = None
    email_message_id: Optional[str] = None
    created_at: datetime
    
    class Config:
        from_attributes = True


# ============================================================================
# AUDIT LOG MODELS
# ============================================================================

class TTicketAuditLogBase(BaseModel):
    """Base model for audit log"""
    entity_type: str = Field(..., max_length=50)
    action: str = Field(..., max_length=50)
    old_value: Optional[str] = None
    new_value: Optional[str] = None
    details: Optional[dict] = Field(default_factory=dict)


class TTicketAuditLogCreate(TTicketAuditLogBase):
    """Model for creating an audit log entry"""
    ticket_id: Optional[int] = None
    entity_id: Optional[int] = None
    user_id: Optional[int] = None


class TTicketAuditLog(TTicketAuditLogBase):
    """Full audit log model with DB fields"""
    id: int
    ticket_id: Optional[int] = None
    entity_id: Optional[int] = None
    user_id: Optional[int] = None
    created_at: datetime
    
    class Config:
        from_attributes = True


# ============================================================================
# RESPONSE MODELS (for API responses)
# ============================================================================

class TicketListResponse(BaseModel):
    """Response model for ticket lists"""
    tickets: List[TTicketWithStats]
    total: int
    page: int = 1
    page_size: int = 50


class WorklogReviewResponse(BaseModel):
    """Response model for worklog review page"""
    worklogs: List[TTicketWorklogWithDetails]
    total: int
    total_hours: Decimal
    total_billable_hours: Decimal


class PrepaidCardBalanceResponse(BaseModel):
    """Response model for prepaid card balance check"""
    card: TPrepaidCardWithStats
    can_deduct: bool
    required_hours: Optional[Decimal] = None
    message: Optional[str] = None


# ============================================================================
# REQUEST MODELS (for specific actions)
# ============================================================================

class TicketStatusUpdateRequest(BaseModel):
    """Request model for updating ticket status"""
    status: TicketStatus
    note: Optional[str] = Field(None, description="Note til audit log")


class WorklogBillingRequest(BaseModel):
    """Request model for marking worklogs as billable"""
    worklog_ids: List[int] = Field(..., min_length=1)
    note: Optional[str] = Field(None, description="Note til audit log")


class PrepaidCardTopUpRequest(BaseModel):
    """Request model for topping up prepaid card"""
    hours: Decimal = Field(..., gt=0, description="Timer at tilføje")
    note: Optional[str] = Field(None, description="Beskrivelse af top-up")


class PrepaidCardDeductRequest(BaseModel):
    """Request model for deducting hours from prepaid card"""
    worklog_id: int = Field(..., gt=0, description="Worklog ID der skal trækkes fra kort")
    hours: Decimal = Field(..., gt=0, description="Timer at trække")


# ============================================================================
# TICKET RELATIONS MODELS (Migration 026)
# ============================================================================

class TicketRelationType(str, Enum):
    """Ticket relation types"""
    MERGED_INTO = "merged_into"
    SPLIT_FROM = "split_from"
    PARENT_OF = "parent_of"
    CHILD_OF = "child_of"
    RELATED_TO = "related_to"


class TTicketRelationBase(BaseModel):
    """Base model for ticket relation"""
    ticket_id: int
    related_ticket_id: int
    relation_type: TicketRelationType
    reason: Optional[str] = None


class TTicketRelationCreate(TTicketRelationBase):
    """Create ticket relation"""
    pass


class TTicketRelation(TTicketRelationBase):
    """Full ticket relation model"""
    id: int
    created_by_user_id: Optional[int] = None
    created_at: datetime

    class Config:
        from_attributes = True


# ============================================================================
# CALENDAR EVENTS MODELS
# ============================================================================

class CalendarEventType(str, Enum):
    """Calendar event types"""
    APPOINTMENT = "appointment"
    DEADLINE = "deadline"
    MILESTONE = "milestone"
    REMINDER = "reminder"
    FOLLOW_UP = "follow_up"


class CalendarEventStatus(str, Enum):
    """Calendar event status"""
    PENDING = "pending"
    CONFIRMED = "confirmed"
    COMPLETED = "completed"
    CANCELLED = "cancelled"


class TTicketCalendarEventBase(BaseModel):
    """Base model for calendar event"""
    ticket_id: int
    title: str = Field(..., min_length=1, max_length=200)
    description: Optional[str] = None
    event_type: CalendarEventType = Field(default=CalendarEventType.APPOINTMENT)
    event_date: date
    event_time: Optional[str] = None
    duration_minutes: Optional[int] = None
    all_day: bool = False
    status: CalendarEventStatus = Field(default=CalendarEventStatus.PENDING)


class TTicketCalendarEventCreate(TTicketCalendarEventBase):
    """Create calendar event"""
    suggested_by_ai: bool = False
    ai_confidence: Optional[Decimal] = None
    ai_source_text: Optional[str] = None


class TTicketCalendarEvent(TTicketCalendarEventBase):
    """Full calendar event model"""
    id: int
    suggested_by_ai: bool = False
    ai_confidence: Optional[Decimal] = None
    ai_source_text: Optional[str] = None
    created_by_user_id: Optional[int] = None
    created_at: datetime
    updated_at: Optional[datetime] = None
    completed_at: Optional[datetime] = None

    class Config:
        from_attributes = True


# ============================================================================
# TEMPLATES MODELS
# ============================================================================

class TTicketTemplateBase(BaseModel):
    """Base model for template"""
    name: str = Field(..., min_length=1, max_length=200)
    description: Optional[str] = None
    category: Optional[str] = None
    subject_template: Optional[str] = Field(None, max_length=500)
    body_template: str = Field(..., min_length=1)
    available_placeholders: Optional[List[str]] = None
    default_attachments: Optional[dict] = None
    is_active: bool = True
    requires_approval: bool = False


class TTicketTemplateCreate(TTicketTemplateBase):
    """Create template"""
    pass


class TTicketTemplate(TTicketTemplateBase):
    """Full template model"""
    id: int
    created_by_user_id: Optional[int] = None
    created_at: datetime
    updated_at: Optional[datetime] = None
    last_used_at: Optional[datetime] = None
    usage_count: int = 0

    class Config:
        from_attributes = True


class TemplateRenderRequest(BaseModel):
    """Request to render template with data"""
    template_id: int
    ticket_id: int
    custom_data: Optional[dict] = None


class TemplateRenderResponse(BaseModel):
    """Rendered template"""
    subject: Optional[str] = None
    body: str
    placeholders_used: List[str]


# ============================================================================
# AI SUGGESTIONS MODELS
# ============================================================================

class AISuggestionType(str, Enum):
    """AI suggestion types"""
    CONTACT_UPDATE = "contact_update"
    NEW_CONTACT = "new_contact"
    CATEGORY = "category"
    TAG = "tag"
    PRIORITY = "priority"
    DEADLINE = "deadline"
    CALENDAR_EVENT = "calendar_event"
    TEMPLATE = "template"
    MERGE = "merge"
    RELATED_TICKET = "related_ticket"


class AISuggestionStatus(str, Enum):
    """AI suggestion status"""
    PENDING = "pending"
    ACCEPTED = "accepted"
    REJECTED = "rejected"
    AUTO_EXPIRED = "auto_expired"


class TTicketAISuggestionBase(BaseModel):
    """Base model for AI suggestion"""
    ticket_id: int
    suggestion_type: AISuggestionType
    suggestion_data: dict  # Struktureret data om forslaget
    confidence: Optional[Decimal] = None
    reasoning: Optional[str] = None
    source_text: Optional[str] = None
    source_comment_id: Optional[int] = None


class TTicketAISuggestionCreate(TTicketAISuggestionBase):
    """Create AI suggestion"""
    expires_at: Optional[datetime] = None


class TTicketAISuggestion(TTicketAISuggestionBase):
    """Full AI suggestion model"""
    id: int
    status: AISuggestionStatus = Field(default=AISuggestionStatus.PENDING)
    reviewed_by_user_id: Optional[int] = None
    reviewed_at: Optional[datetime] = None
    created_at: datetime
    expires_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class AISuggestionReviewRequest(BaseModel):
    """Request to accept/reject AI suggestion"""
    action: str = Field(..., pattern="^(accept|reject)$")
    note: Optional[str] = None


# ============================================================================
# EMAIL METADATA MODELS
# ============================================================================

class TTicketEmailMetadataBase(BaseModel):
    """Base model for email metadata"""
    ticket_id: int
    message_id: Optional[str] = None
    in_reply_to: Optional[str] = None
    references: Optional[str] = None
    from_email: str
    from_name: Optional[str] = None
    from_signature: Optional[str] = None


class TTicketEmailMetadataCreate(TTicketEmailMetadataBase):
    """Create email metadata"""
    matched_contact_id: Optional[int] = None
    match_confidence: Optional[Decimal] = None
    match_method: Optional[str] = None
    suggested_contacts: Optional[dict] = None
    extracted_phone: Optional[str] = None
    extracted_address: Optional[str] = None
    extracted_company: Optional[str] = None
    extracted_title: Optional[str] = None


class TTicketEmailMetadata(TTicketEmailMetadataCreate):
    """Full email metadata model"""
    id: int
    created_at: datetime
    updated_at: Optional[datetime] = None

    class Config:
        from_attributes = True


# ============================================================================
# AUDIT LOG MODELS
# ============================================================================

class TTicketAuditLog(BaseModel):
    """Audit log entry"""
    id: int
    ticket_id: int
    action: str
    field_name: Optional[str] = None
    old_value: Optional[str] = None
    new_value: Optional[str] = None
    user_id: Optional[int] = None
    performed_at: datetime
    reason: Optional[str] = None
    metadata: Optional[dict] = None

    class Config:
        from_attributes = True


# ============================================================================
# EXTENDED REQUEST MODELS
# ============================================================================

class TicketMergeRequest(BaseModel):
    """Request to merge tickets"""
    source_ticket_ids: List[int] = Field(..., min_length=1, description="Tickets at lægge sammen")
    target_ticket_id: int = Field(..., description="Primær ticket der skal beholdes")
    reason: Optional[str] = Field(None, description="Hvorfor lægges de sammen")


class TicketSplitRequest(BaseModel):
    """Request to split ticket"""
    source_ticket_id: int = Field(..., description="Ticket at splitte")
    comment_ids: List[int] = Field(..., min_length=1, description="Kommentarer til ny ticket")
    new_subject: str = Field(..., min_length=1, description="Emne på ny ticket")
    new_description: Optional[str] = Field(None, description="Beskrivelse på ny ticket")
    reason: Optional[str] = Field(None, description="Hvorfor splittes ticketen")


class TicketDeadlineUpdateRequest(BaseModel):
    """Request to update ticket deadline"""
    deadline: Optional[datetime] = None
    reason: Optional[str] = None
