import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
import mongoose, { Document, Types } from 'mongoose'
import { piiPlugin } from '../encryption/pii-plugin'

// ─── Enums ─────────────────────────────────────────────────────────────────

export type ClientType = 'individual' | 'corporate'
export type ClientStatus = 'prospect' | 'conflict_check' | 'active' | 'closed' | 'rejected'
export type MatterStatus = 'open' | 'pending' | 'closed' | 'archived'
export type PracticeArea = 'immigration' | 'corporate' | 'civil_litigation' | 'property' | 'family' | 'employment' | 'criminal' | 'other'
export type PartyRole = 'client' | 'opposing_party' | 'opposing_counsel' | 'witness' | 'judge' | 'court_officer' | 'co_counsel' | 'other'
export type HearingStatus = 'scheduled' | 'confirmed' | 'adjourned' | 'completed' | 'cancelled'
export type DocumentPrivilege = 'privileged' | 'non_privileged' | 'work_product'
export type RetainerTxType = 'intake' | 'disbursement' | 'refund' | 'invoice_applied'
export type ConflictResult = 'clear' | 'conflict_found' | 'waived' | 'pending'

// ─── RetainerTransaction ───────────────────────────────────────────────────

export interface RetainerTransaction {
  txId: string
  type: RetainerTxType
  amount: number          // positive = intake, negative = disbursement
  currency: string
  date: Date
  description: string
  matterId?: string
  invoiceRef?: string
  createdBy: string
}

// ─── ClientFolder ──────────────────────────────────────────────────────────

@Schema({ timestamps: true, collection: 'client_folders' })
export class ClientFolder {
  @Prop({ required: true, unique: true, index: true })
  folderNumber: string    // e.g. CF-2024-0001

  @Prop({ required: true, enum: ['individual', 'corporate'] })
  clientType: ClientType

  // Individual fields
  @Prop() firstName?: string
  @Prop() lastName?: string
  @Prop() nationality?: string
  @Prop() passportNumber?: string
  @Prop() idType?: string
  @Prop() visaNumber?: string
  @Prop() visaType?: string
  @Prop() visaExpiry?: Date
  @Prop() arrivalDate?: Date          // last entry date — anchor for 90-day reporting
  @Prop() permitExpiry?: Date         // work permit / BOI permit expiry
  @Prop() dateOfBirth?: Date

  // Corporate fields
  @Prop() companyName?: string
  @Prop() registrationNumber?: string
  @Prop() boiStatus?: string
  @Prop() directors?: string[]

  // Shared
  @Prop({ required: true }) displayName: string   // derived: "Smith, James" or company name

  // Primary contact (legacy + primary entry)
  @Prop() email?: string
  @Prop() phone?: string
  @Prop() lineId?: string
  @Prop() address?: string  // legacy formatted string from first address entry

  @Prop({ type: [Object], default: [] })
  addresses: { line1: string; line2?: string; city?: string; state?: string; postal?: string; country: string; type: string }[]

  @Prop({ type: [Object], default: [] })
  folderTeam: { name: string; role: string; firm?: string; email?: string; phone?: string; notes?: string }[]

  @Prop({ type: [Object], default: [] })
  folderParties: { name: string; type: string; organization?: string; role?: string; email?: string; phone?: string; barNumber?: string; notes?: string }[]

  @Prop({ type: [Object], default: [] })
  folderAgencies: {
    id: string; name: string; agencyType: string; country?: string;
    contactPerson?: string; phone?: string; email?: string;
    website?: string; referenceNumber?: string; notes?: string
  }[]

  @Prop({ type: [Object], default: [] })
  complianceEvents: {
    id: string; title: string; agencyId: string; agencyName: string;
    eventType: string; date: string; status: string;
    matterId?: string; matterTitle?: string; referenceNumber?: string; notes?: string
  }[]

  // Structured multi-contact
  @Prop({ type: [Object], default: [] })
  phones: { countryCode: string; dialCode: string; number: string; type: string }[]

  @Prop({ type: [Object], default: [] })
  emails: { address: string; type: string }[]

  @Prop() region?: string   // geographic region e.g. "Thailand", "Southeast Asia", "Europe"

  @Prop({ required: true, enum: ['prospect', 'conflict_check', 'active', 'closed', 'rejected'], default: 'prospect' })
  status: ClientStatus

  @Prop({ required: true })
  originatingAttorney: string

  @Prop({ required: true })
  responsibleAttorney: string

  @Prop()
  engagementDate?: Date

  @Prop()
  engagementLetterRef?: string

  @Prop()
  closedDate?: Date

  @Prop()
  closedReason?: string

  @Prop({ default: 0 })
  retainerBalance: number

  @Prop({ default: 20000 })
  retainerThreshold: number

  @Prop({ default: 'THB' })
  currency: string

  @Prop({ type: [Object], default: [] })
  retainerLedger: RetainerTransaction[]

  // Document management
  @Prop({ default: 0 })
  batesCounter: number   // next sequence number — incremented atomically on each upload

  @Prop({ type: [Object], default: [] })
  docFolders: {
    _id: string
    name: string
    icon: string    // remixicon class e.g. ri-mail-line
    color: string   // hex
    isSystem: boolean
    createdAt: Date
    createdBy: string
  }[]

  @Prop()
  conflictCheckId?: string

  @Prop()
  notes?: string

  @Prop({ default: false })
  archived: boolean

  // ─── Billing Configuration ──────────────────────────────────────────────
  @Prop({ type: Object })
  billingConfig?: {
    billingType: 'hourly' | 'fixed' | 'retainer' | 'contingency' | 'hybrid'

    // Hourly / rate schedule
    defaultHourlyRate: number
    rateSchedule: { attorney: string; title?: string; rate: number }[]

    // Retainer maintenance
    retainerRequired: boolean
    retainerAmount: number         // replenishment target amount
    retainerThreshold: number      // minimum balance before alert/top-up request
    autoReplenish: boolean         // send replenishment reminder automatically

    // Billing frequency
    billingFrequency: 'monthly' | 'bi_monthly' | 'quarterly' | 'upon_completion' | 'as_incurred' | 'milestone'
    billingDayOfMonth?: number     // 1–28; for monthly/bi-monthly

    // Payment terms
    paymentTermsDays: number       // 0 = due on receipt, 15, 30, 45, etc.

    // VAT
    vatExempt: boolean
    vatRate: number                // default 0.07
    vatRegNumber?: string

    // Invoice delivery
    invoiceDelivery: 'email' | 'postal' | 'both' | 'none'

    // Notes
    billingNotes?: string

    updatedBy?: string
    updatedAt?: Date
  }
}

export const ClientFolderSchema = SchemaFactory.createForClass(ClientFolder)
ClientFolderSchema.plugin(piiPlugin, {
  fields: [
    'firstName', 'lastName', 'displayName',
    'email', 'phone', 'lineId', 'address',
    'passportNumber', 'visaNumber', 'companyName',
    'registrationNumber', 'notes',
  ],
  searchable: ['firstName', 'lastName', 'displayName', 'email', 'companyName'],
})
export type ClientFolderDocument = ClientFolder & Document

// ─── Party ─────────────────────────────────────────────────────────────────

@Schema({ timestamps: true, collection: 'parties' })
export class Party {
  @Prop({ required: true })
  displayName: string

  @Prop({ required: true, enum: ['individual', 'corporate'] })
  partyType: ClientType

  @Prop({ required: true })
  role: PartyRole

  @Prop() email?: string
  @Prop() phone?: string
  @Prop() firmName?: string       // for opposing counsel
  @Prop() barNumber?: string
  @Prop() nationality?: string
  @Prop() notes?: string

  // Which matters this party appears in
  @Prop({ type: [Types.ObjectId], ref: 'Matter', default: [] })
  matterIds: Types.ObjectId[]
}

export const PartySchema = SchemaFactory.createForClass(Party)
PartySchema.plugin(piiPlugin, {
  fields:     ['displayName', 'email', 'phone', 'barNumber', 'notes'],
  searchable: ['displayName', 'email'],
})
export type PartyDocument = Party & Document

// ─── Matter ────────────────────────────────────────────────────────────────

@Schema({ timestamps: true, collection: 'matters' })
export class Matter {
  @Prop({ required: true, unique: true, index: true })
  matterNumber: string    // e.g. M-2024-0042-IMM

  @Prop({ type: Types.ObjectId, ref: 'ClientFolder', required: true, index: true })
  clientFolderId: Types.ObjectId

  @Prop({ required: true })
  title: string           // e.g. "TM.7 Extension — James Smith"

  @Prop({ required: true, enum: ['immigration', 'corporate', 'civil_litigation', 'property', 'family', 'employment', 'criminal', 'other'] })
  practiceArea: PracticeArea

  @Prop() subType?: string        // e.g. "visa_extension", "company_registration"

  @Prop({ required: true, enum: ['open', 'pending', 'closed', 'archived'], default: 'open' })
  status: MatterStatus

  @Prop({ required: true })
  responsibleAttorney: string

  @Prop({ type: [String], default: [] })
  teamMembers: string[]

  @Prop({ required: true })
  openedDate: Date

  @Prop()
  closedDate?: Date

  @Prop()
  closedOutcome?: string

  @Prop({ type: [Types.ObjectId], ref: 'Party', default: [] })
  partyIds: Types.ObjectId[]

  @Prop()
  courtReference?: string         // court case number

  @Prop()
  opposingCounsel?: string

  @Prop()
  nextActionDate?: Date

  @Prop()
  nextActionDescription?: string

  @Prop()
  notes?: string

  @Prop({ default: 0 })
  totalBilled: number

  @Prop({ default: 0 })
  totalPaid: number

  @Prop({ default: 'THB' })
  currency: string

  // Extended data for annual compliance matters (subType === 'annual_compliance')
  // Stored as a flexible sub-document so the annual-compliance module can evolve
  // independently of the base matter schema.
  @Prop({ type: Object, default: null })
  annualCompliance?: Record<string, any>
}

export const MatterSchema = SchemaFactory.createForClass(Matter)
export type MatterDocument = Matter & Document

// ─── Hearing ───────────────────────────────────────────────────────────────

@Schema({ timestamps: true, collection: 'hearings' })
export class Hearing {
  @Prop({ type: Types.ObjectId, ref: 'Matter', required: true, index: true })
  matterId: Types.ObjectId

  @Prop({ type: Types.ObjectId, ref: 'ClientFolder', required: true })
  clientFolderId: Types.ObjectId

  @Prop({ required: true })
  date: Date

  @Prop({ required: true })
  time: string            // "09:30"

  @Prop({ required: true })
  court: string

  @Prop() room?: string
  @Prop() judge?: string
  @Prop() hearingType?: string    // e.g. "Examination of witnesses", "Judgment reading"

  @Prop({ required: true, enum: ['scheduled', 'confirmed', 'adjourned', 'completed', 'cancelled'], default: 'scheduled' })
  status: HearingStatus

  @Prop()
  outcome?: string

  @Prop()
  nextHearingDate?: Date

  @Prop()
  notes?: string

  @Prop()
  attendingAttorney?: string

  @Prop({ default: false })
  reminderSent: boolean
}

export const HearingSchema = SchemaFactory.createForClass(Hearing)
export type HearingDocument = Hearing & Document

// ─── LegalDocument ─────────────────────────────────────────────────────────

export type AiStatus = 'pending' | 'processing' | 'classified' | 'failed'

@Schema({ timestamps: true, collection: 'legal_documents' })
export class LegalDocument {
  @Prop({ type: Types.ObjectId, ref: 'ClientFolder', required: true, index: true })
  clientFolderId: Types.ObjectId

  @Prop({ type: Types.ObjectId, ref: 'Matter', index: true })
  matterId?: Types.ObjectId       // optional — some docs are folder-level

  // Bates identifier — e.g. CF-2025-0042-00001
  @Prop({ required: true, unique: true, index: true })
  batesNumber: string

  // Doc-folder within client folder (null = Inbox / unclassified)
  @Prop() folderId?: string

  // File metadata
  @Prop({ required: true })
  originalName: string            // original upload filename

  @Prop({ required: true })
  fileName: string                // stored filename (batesNumber + ext)

  @Prop({ required: true })
  storageKey: string              // relative path under uploads/

  @Prop() mimeType?: string
  @Prop() fileSize?: number

  // Document content info
  @Prop({ required: true })
  title: string                   // initially = originalName, updated by AI

  @Prop() documentType?: string   // AI-extracted: contract | court_filing | identity | etc.

  @Prop({ required: true, enum: ['privileged', 'non_privileged', 'work_product'], default: 'non_privileged' })
  privilege: DocumentPrivilege

  // AI classification
  @Prop({ required: true, enum: ['pending', 'processing', 'classified', 'failed'], default: 'pending' })
  aiStatus: AiStatus

  @Prop() summary?: string        // AI-generated
  @Prop({ type: [String], default: [] }) parties: string[]
  @Prop() documentDate?: Date     // date on the document itself
  @Prop() aiConfidence?: number   // 0-1
  @Prop() detectedLanguage?: string   // 'th' | 'en' | 'mixed' | 'other'

  @Prop({ default: false })
  classified: boolean

  @Prop() classificationNotes?: string

  @Prop({ type: [String], default: [] })
  tags: string[]

  @Prop()
  uploadedBy?: string

  @Prop()
  receivedDate?: Date

  // Translation support
  @Prop() translatedSummary?: string        // cached translated summary
  @Prop() translatedSummaryLang?: string    // 'en' | 'th'
  @Prop({ type: Types.ObjectId, ref: 'LegalDocument' })
  sourceDocumentId?: Types.ObjectId         // set when isTranslation = true
  @Prop({ default: false }) isTranslation?: boolean
  @Prop() translationLanguage?: string      // 'en' | 'th'

  // Legacy fields kept for compat
  @Prop() storageRef?: string
  @Prop() version?: string
  @Prop() notes?: string
  @Prop() signed?: boolean
}

export const LegalDocumentSchema = SchemaFactory.createForClass(LegalDocument)
export type LegalDocumentDocument = LegalDocument & Document

// ─── TimeEntry ─────────────────────────────────────────────────────────────

@Schema({ timestamps: true, collection: 'time_entries' })
export class TimeEntry {
  @Prop({ type: Types.ObjectId, ref: 'Matter', required: true, index: true })
  matterId: Types.ObjectId

  @Prop({ type: Types.ObjectId, ref: 'ClientFolder', required: true })
  clientFolderId: Types.ObjectId

  @Prop({ required: true })
  attorney: string

  @Prop({ required: true })
  date: Date

  @Prop({ required: true })
  durationMinutes: number

  @Prop() taskCode?: string       // UTBMS or custom

  @Prop({ required: true })
  description: string

  @Prop({ required: true })
  ratePerHour: number

  @Prop({ required: true })
  currency: string

  @Prop()
  invoiceRef?: string

  @Prop({ default: false })
  billed: boolean
}

export const TimeEntrySchema = SchemaFactory.createForClass(TimeEntry)
export type TimeEntryDocument = TimeEntry & Document

// ─── Invoice ────────────────────────────────────────────────────────────────

export type InvoiceStatus = 'draft' | 'sent' | 'paid' | 'void'

export interface InvoiceLineItem {
  description: string
  quantity: number      // hours for hourly, 1 for fixed fee
  unitPrice: number
  amount: number
  timeEntryIds?: string[]
  expenseIds?: string[]
}

@Schema({ timestamps: true, collection: 'invoices' })
export class Invoice {
  @Prop({ required: true, unique: true, index: true })
  invoiceNumber: string   // e.g. INV-2026-0001

  @Prop({ type: Types.ObjectId, ref: 'ClientFolder', required: true, index: true })
  clientFolderId: Types.ObjectId

  @Prop({ type: Types.ObjectId, ref: 'Matter', index: true })
  matterId?: Types.ObjectId

  @Prop({ type: [Object], required: true })
  lineItems: InvoiceLineItem[]

  @Prop({ required: true })
  subtotal: number

  @Prop({ default: 0.07 })
  vatRate: number         // Thailand 7% VAT; 0 if exempt

  @Prop({ required: true })
  vatAmount: number

  @Prop({ required: true })
  total: number

  @Prop({ default: 'THB' })
  currency: string

  @Prop({ required: true, enum: ['draft', 'sent', 'paid', 'void'], default: 'draft' })
  status: InvoiceStatus

  @Prop({ required: true })
  issueDate: Date

  @Prop({ required: true })
  dueDate: Date           // default: issueDate + 30 days

  @Prop() paidDate?: Date
  @Prop() paidAmount?: number

  @Prop() notes?: string

  @Prop({ required: true })
  createdBy: string
}

export const InvoiceSchema = SchemaFactory.createForClass(Invoice)
export type InvoiceDocument = Invoice & Document

// ─── Expense ───────────────────────────────────────────────────────────────

export type ExpenseCategory =
  | 'court_filing' | 'translation' | 'notarization' | 'travel' | 'accommodation'
  | 'courier' | 'printing' | 'government_fee' | 'expert_witness' | 'other'

export type ExpenseStatus = 'pending' | 'billed' | 'reimbursed' | 'written_off'

@Schema({ timestamps: true, collection: 'expenses' })
export class Expense {
  @Prop({ required: true, index: true })
  clientFolderId: string

  @Prop({ index: true })
  matterId?: string

  @Prop({ required: true })
  description: string

  @Prop({ required: true, enum: ['court_filing','translation','notarization','travel','accommodation','courier','printing','government_fee','expert_witness','other'] })
  category: ExpenseCategory

  @Prop({ required: true })
  amount: number

  @Prop({ default: 'THB' })
  currency: string

  @Prop({ required: true })
  expenseDate: Date

  @Prop({ default: false })
  billable: boolean

  @Prop({ default: false })
  vatIncluded: boolean

  @Prop({ default: 0 })
  vatRate: number

  @Prop({ enum: ['pending','billed','reimbursed','written_off'], default: 'pending' })
  status: ExpenseStatus

  @Prop()
  invoiceId?: string

  @Prop()
  receiptUrl?: string   // uploaded receipt image/doc path

  @Prop()
  notes?: string

  @Prop({ required: true })
  createdBy: string
}

export const ExpenseSchema = SchemaFactory.createForClass(Expense)
export type ExpenseDocument = Expense & Document

// ─── Trust Account ─────────────────────────────────────────────────────────
// One TrustAccount per client folder. TrustTransaction records every movement.
// 3-way reconciliation: book balance (sum of txns) == bank statement balance
//   == sum of all client ledger balances.

export type TrustTxType =
  | 'receipt'        // funds received from client into trust
  | 'disbursement'   // funds paid out on behalf of client (costs)
  | 'transfer_out'   // transfer to another client trust account (rare)
  | 'interest'       // interest earned (jurisdiction-dependent)
  | 'fee_draw'       // draw against earned fees (must follow invoice)
  | 'refund'         // refund of excess trust funds back to client
  | 'adjustment'     // bank rec adjustment / error correction

@Schema({ timestamps: true, collection: 'trust_transactions' })
export class TrustTransaction {
  @Prop({ required: true, index: true })
  clientFolderId: string

  @Prop()
  matterId?: string

  @Prop({ required: true })
  txDate: Date

  @Prop({ required: true, enum: ['receipt','disbursement','transfer_out','interest','fee_draw','refund','adjustment'] })
  type: TrustTxType

  @Prop({ required: true })
  amount: number          // always positive; direction inferred from type

  @Prop({ default: 'THB' })
  currency: string

  @Prop({ required: true })
  description: string

  @Prop()
  reference?: string      // cheque #, wire ref, invoice #, etc.

  @Prop()
  invoiceId?: string      // for fee_draw, link to invoice

  @Prop({ default: false })
  reconciled: boolean     // has been matched to bank statement

  @Prop()
  bankStatementRef?: string  // bank statement line reference

  @Prop({ required: true })
  createdBy: string
}

export const TrustTransactionSchema = SchemaFactory.createForClass(TrustTransaction)
export type TrustTransactionDocument = TrustTransaction & Document

@Schema({ timestamps: true, collection: 'trust_accounts' })
export class TrustAccount {
  @Prop({ required: true, unique: true, index: true })
  clientFolderId: string

  @Prop({ default: 'THB' })
  currency: string

  @Prop({ default: 0 })
  bookBalance: number     // running sum of all transactions

  @Prop({ default: 0 })
  bankBalance: number     // last-confirmed bank statement balance

  @Prop()
  lastReconciledDate?: Date

  @Prop()
  lastReconciledBy?: string

  @Prop({ default: false })
  isReconciled: boolean   // book == bank as of lastReconciledDate

  @Prop()
  accountNumber?: string  // physical trust bank account number (firm-level)

  @Prop()
  notes?: string
}

export const TrustAccountSchema = SchemaFactory.createForClass(TrustAccount)
export type TrustAccountDocument = TrustAccount & Document

// ─── ConflictCheck ─────────────────────────────────────────────────────────

@Schema({ timestamps: true, collection: 'conflict_checks' })
export class ConflictCheck {
  @Prop({ required: true })
  checkNumber: string

  @Prop({ type: Types.ObjectId, ref: 'ClientFolder', required: true })
  clientFolderId: Types.ObjectId

  @Prop({ required: true })
  requestedBy: string

  @Prop({ required: true })
  requestDate: Date

  @Prop({ type: [String], default: [] })
  searchTerms: string[]           // names, entities checked

  @Prop({ type: [Object], default: [] })
  hits: { folderId: string; folderNumber: string; displayName: string; relationship: string; details: string }[]

  @Prop({ required: true, enum: ['clear', 'conflict_found', 'waived', 'pending'], default: 'pending' })
  result: ConflictResult

  @Prop()
  reviewedBy?: string

  @Prop()
  reviewDate?: Date

  @Prop()
  waiverRef?: string              // if waived, reference to signed waiver

  @Prop()
  notes?: string
}

export const ConflictCheckSchema = SchemaFactory.createForClass(ConflictCheck)

// ─── Email ──────────────────────────────────────────────────────────────────

export type EmailDirection  = 'inbound' | 'outbound'
export type EmailAssocStatus =
  | 'auto_matched'     // email address matched a client folder exactly
  | 'confirmed'        // user explicitly confirmed the association
  | 'pending_review'   // candidates found — awaiting user decision
  | 'unassociated'     // no match found at all

export interface EmailAddress {
  address: string
  name?: string
}

export interface EmailAttachment {
  filename: string
  contentType: string
  size: number
  storageKey?: string
}

export interface AssociationCandidate {
  clientFolderId: string
  displayName: string
  folderNumber: string
  matterId?: string
  matterNumber?: string
  matterTitle?: string
  confidence: number    // 0–1
  reason: string        // 'email_match' | 'name_match' | 'open_matter'
}

@Schema({ timestamps: true, collection: 'emails' })
export class Email {
  @Prop({ required: true, unique: true, index: true })
  messageId: string               // from Message-ID header

  @Prop({ index: true })
  threadId: string                // derived: first messageId in chain

  @Prop()
  inReplyTo?: string

  @Prop({ type: [String], default: [] })
  references: string[]

  @Prop({ required: true, enum: ['inbound', 'outbound'], index: true })
  direction: EmailDirection

  @Prop({ type: Object, required: true })
  from: EmailAddress

  @Prop({ type: [Object], default: [] })
  to: EmailAddress[]

  @Prop({ type: [Object], default: [] })
  cc: EmailAddress[]

  @Prop({ type: [Object], default: [] })
  bcc: EmailAddress[]

  @Prop({ required: true })
  subject: string

  @Prop()
  bodyText?: string

  @Prop()
  bodyHtml?: string

  @Prop({ type: [Object], default: [] })
  attachments: EmailAttachment[]

  @Prop({ required: true })
  receivedAt: Date

  // Association
  @Prop({ index: true })
  clientFolderId?: string

  @Prop({ index: true })
  matterId?: string

  @Prop({
    required: true,
    enum: ['auto_matched', 'confirmed', 'pending_review', 'unassociated'],
    default: 'pending_review',
    index: true,
  })
  associationStatus: EmailAssocStatus

  @Prop()
  associationConfirmedBy?: string

  @Prop()
  associationConfirmedAt?: Date

  @Prop({ type: [Object], default: [] })
  associationCandidates: AssociationCandidate[]

  // Forwarded-by: which registered user forwarded this inbound email
  @Prop()
  forwardedBy?: string

  @Prop({ default: false })
  isRead: boolean

  @Prop({ default: false })
  isArchived: boolean

  @Prop({ type: [String], default: [] })
  tags: string[]
}

export const EmailSchema = SchemaFactory.createForClass(Email)

// Encrypt email content fields
EmailSchema.plugin(piiPlugin, {
  fields:     ['subject', 'bodyText', 'bodyHtml'],
  searchable: [],
})

// Add hash index fields for email address association lookups
EmailSchema.add({
  fromAddressHash: { type: String, index: true, select: false },
  toAddressHashes: { type: [String], default: [], index: true, select: false },
} as any)

// Encrypt from/to addresses and maintain hash index
EmailSchema.pre('save', function (next) {
  const { _getEnc } = require('../encryption/pii-plugin') as typeof import('../encryption/pii-plugin')
  const enc = _getEnc()
  if (!enc) return next()

  const doc = this as any

  // Hash from address for association lookups
  if (doc.from?.address) {
    doc.fromAddressHash = enc.hash(doc.from.address)
    doc.from = {
      address: enc.encrypt(doc.from.address),
      name:    doc.from.name ? enc.encrypt(doc.from.name) : doc.from.name,
    }
  }

  // Hash + encrypt to addresses
  const toHashes: string[] = []
  if (Array.isArray(doc.to)) {
    doc.to = doc.to.map((addr: any) => {
      if (addr.address) toHashes.push(enc.hash(addr.address))
      return {
        address: addr.address ? enc.encrypt(addr.address) : addr.address,
        name:    addr.name    ? enc.encrypt(addr.name)    : addr.name,
      }
    })
  }
  doc.toAddressHashes = toHashes

  // Encrypt cc/bcc names and addresses
  for (const field of ['cc', 'bcc'] as const) {
    if (Array.isArray(doc[field])) {
      doc[field] = doc[field].map((addr: any) => ({
        address: addr.address ? enc.encrypt(addr.address) : addr.address,
        name:    addr.name    ? enc.encrypt(addr.name)    : addr.name,
      }))
    }
  }

  next()
})

// Decrypt from/to on document hydration
EmailSchema.post('init', function (doc: any) {
  const { _getEnc } = require('../encryption/pii-plugin') as typeof import('../encryption/pii-plugin')
  const enc = _getEnc()
  if (!enc) return

  if (doc.from?.address) {
    doc.from = {
      address: enc.decrypt(doc.from.address),
      name:    doc.from.name ? enc.decrypt(doc.from.name) : doc.from.name,
    }
  }
  for (const field of ['to', 'cc', 'bcc']) {
    if (Array.isArray(doc[field])) {
      doc[field] = doc[field].map((addr: any) => ({
        address: addr.address ? enc.decrypt(addr.address) : addr.address,
        name:    addr.name    ? enc.decrypt(addr.name)    : addr.name,
      }))
    }
  }
})

export type EmailDocument = Email & Document

// ─── UserEmailAccount ────────────────────────────────────────────────────────
// Registered attorney / staff email addresses. The system uses this to:
//   1. Identify the sender when emails arrive forwarded to the SMTP
//   2. Populate the "forwardedBy" field for routing

@Schema({ timestamps: true, collection: 'user_email_accounts' })
export class UserEmailAccount {
  @Prop({ required: true, unique: true, index: true, lowercase: true, trim: true })
  emailAddress: string

  @Prop({ required: true })
  displayName: string

  @Prop({ default: true })
  isActive: boolean

  @Prop()
  notes?: string
}

export const UserEmailAccountSchema = SchemaFactory.createForClass(UserEmailAccount)
export type UserEmailAccountDocument = UserEmailAccount & Document

// ─── EmailServerSettings ─────────────────────────────────────────────────────
// Singleton document (key = 'email') — stored in system_settings collection.

@Schema({ collection: 'system_settings' })
export class EmailServerSettings {
  @Prop({ required: true, unique: true })
  key: string    // always 'email'

  // Inbound SMTP listener (embedded server, port 2525)
  @Prop({ default: 2525 })
  smtpListenPort: number

  @Prop({ default: '0.0.0.0' })
  smtpListenHost: string

  // IMAP polling (optional — alternative/supplement to SMTP listener)
  @Prop({ default: false })
  imapEnabled: boolean

  @Prop() imapHost?: string
  @Prop({ default: 993 }) imapPort: number
  @Prop({ default: true }) imapSsl: boolean
  @Prop() imapUser?: string
  @Prop() imapPassword?: string
  @Prop({ default: 'INBOX' }) imapFolder: string
  @Prop({ default: 60 }) imapPollIntervalSeconds: number

  // Outbound SMTP relay
  @Prop() outboundSmtpHost?: string
  @Prop({ default: 587 }) outboundSmtpPort: number
  @Prop({ default: false }) outboundSmtpSsl: boolean
  @Prop() outboundSmtpUser?: string
  @Prop() outboundSmtpPassword?: string
  @Prop() outboundFromAddress?: string
  @Prop() outboundFromName?: string
}

export const EmailServerSettingsSchema = SchemaFactory.createForClass(EmailServerSettings)
export type EmailServerSettingsDocument = EmailServerSettings & Document
export type ConflictCheckDocument = ConflictCheck & Document

// ─── AgentSession ─────────────────────────────────────────────────────────────

@Schema({ timestamps: true, collection: 'agent_sessions' })
export class AgentSession {
  @Prop({ required: true, unique: true }) sessionId: string
  // Stored as plain objects — compatible with Anthropic MessageParam[]
  @Prop({ type: [mongoose.Schema.Types.Mixed], default: [] }) messages: any[]
  @Prop({ default: 'active' }) status: string
}

export const AgentSessionSchema = SchemaFactory.createForClass(AgentSession)
export type AgentSessionDocument = AgentSession & Document

// ─── FormTemplate ─────────────────────────────────────────────────────────────
// A PDF template with field coordinate mappings for auto-fill generation.
// storageKey points to the blank government/standard PDF in object storage.

export interface FormFieldMapping {
  fieldId: string                 // unique within template, e.g. "applicant_firstname"
  label: string                   // human-readable, e.g. "Applicant First Name"
  // Coordinate-mode fields (fillMode === 'coordinate')
  page?: number                   // 1-based PDF page number
  x?: number                      // points from left edge
  y?: number                      // points from bottom edge (pdf-lib coordinate system)
  fontSize?: number               // default 10
  fontFamily?: string             // default Helvetica
  // AcroForm-mode field (fillMode === 'acroform')
  acroFieldName?: string          // PDF form field name as embedded in the PDF
  // Data binding: "client.firstName" | "matter.title" | "static"
  dataSource: string
  staticValue?: string            // only when dataSource === 'static'
  maxLength?: number              // truncate if set
  dateFormat?: string             // e.g. "DD/MM/YYYY"
}

@Schema({ timestamps: true, collection: 'form_templates' })
export class FormTemplate {
  @Prop({ required: true })
  name: string                    // e.g. "TM.7 — Extension of Stay"

  @Prop()
  description?: string

  @Prop({ enum: ['immigration', 'corporate', 'civil_litigation', 'property', 'family', 'employment', 'criminal', 'other', 'universal'], default: 'universal' })
  practiceArea: string

  // Where to find the blank PDF on disk.
  // For stock forms: auto-downloaded from sourceUrl on first generate.
  // For custom forms: uploaded by user via admin panel.
  @Prop({ default: '' })
  storageKey: string

  @Prop()
  originalFilename?: string

  // Official source URL — used to fetch (or re-fetch) the blank PDF
  @Prop()
  sourceUrl?: string

  // Fill strategy:
  //   'coordinate'    = draw text at x/y positions on a blank PDF
  //   'acroform'      = fill PDF AcroForm fields by name
  //   'html-template' = render a Handlebars HTML template to PDF via headless Chrome
  @Prop({ default: 'coordinate', enum: ['coordinate', 'acroform', 'html-template'] })
  fillMode: 'coordinate' | 'acroform' | 'html-template'

  @Prop({ type: [Object], default: [] })
  fields: FormFieldMapping[]

  @Prop({ default: true })
  isActive: boolean

  // System (stock library) templates are protected from deletion
  @Prop({ default: false })
  isSystem: boolean

  // Stable identifier for stock library entries — used to avoid re-seeding on restart
  @Prop({ index: true, sparse: true })
  stockId?: string

  // True when field coordinates/names have not been verified against the actual PDF
  @Prop({ default: false })
  needsCalibration: boolean

  @Prop()
  createdBy?: string

  @Prop()
  notes?: string
}

export const FormTemplateSchema = SchemaFactory.createForClass(FormTemplate)
export type FormTemplateDocument = FormTemplate & Document

// ─── FormGenerationLog ────────────────────────────────────────────────────────
// Audit trail for every filled-form PDF generated by the system.

@Schema({ timestamps: true, collection: 'form_generation_logs' })
export class FormGenerationLog {
  @Prop({ required: true, index: true })
  formTemplateId: string

  @Prop({ required: true })
  formTemplateName: string

  @Prop({ required: true, index: true })
  matterId: string

  @Prop({ required: true, index: true })
  clientFolderId: string

  @Prop({ required: true })
  storageKey: string              // object-storage key for the generated (filled) PDF

  @Prop()
  generatedBy?: string

  @Prop()
  legalDocumentId?: string        // set after auto-filing to document cabinet
}

export const FormGenerationLogSchema = SchemaFactory.createForClass(FormGenerationLog)
export type FormGenerationLogDocument = FormGenerationLog & Document

// ─── WorkflowTemplate ─────────────────────────────────────────────────────────
// Reusable procedural checklist (e.g. "TM.7 Extension of Stay — Full Workflow").
// Instantiated per matter into a MatterWorkflow on demand.

export interface WorkflowStepDef {
  stepId: string                  // stable identifier within template, e.g. "step_01"
  order: number                   // 1-based display order
  title: string
  description?: string
  mandatory: boolean
  linkedFormTemplateId?: string   // pre-wire a "Generate Form" action to this step
  deadlineDays?: number           // days after matter openedDate (null = no automatic deadline)
  dueAfterStepId?: string         // relative deadline: N days after this step completes
}

@Schema({ timestamps: true, collection: 'workflow_templates' })
export class WorkflowTemplate {
  @Prop({ required: true })
  name: string                    // e.g. "Work Permit Application — BOI"

  @Prop()
  description?: string

  @Prop({ enum: ['immigration', 'corporate', 'civil_litigation', 'property', 'family', 'employment', 'criminal', 'other', 'universal'], default: 'universal' })
  practiceArea: string

  @Prop({ type: [Object], default: [] })
  steps: WorkflowStepDef[]

  @Prop({ default: true })
  isActive: boolean

  @Prop({ default: false })
  isSystem: boolean               // system-provided templates cannot be deleted

  @Prop({ index: true })
  stockId?: string                // stable identifier for system templates (e.g. "imm_retirement_visa")

  @Prop()
  createdBy?: string

  @Prop()
  notes?: string
}

export const WorkflowTemplateSchema = SchemaFactory.createForClass(WorkflowTemplate)
export type WorkflowTemplateDocument = WorkflowTemplate & Document

// ─── MatterWorkflow ───────────────────────────────────────────────────────────
// A live workflow instance attached to one matter.
// Created by "Apply Workflow" action; steps are tracked individually.

export type WorkflowStepStatus = 'pending' | 'in_progress' | 'completed' | 'skipped'

export interface MatterWorkflowStep {
  stepId: string
  order: number
  title: string
  description?: string
  mandatory: boolean
  linkedFormTemplateId?: string
  status: WorkflowStepStatus
  dueDate?: Date
  completedAt?: Date
  completedBy?: string
  notes?: string
}

@Schema({ timestamps: true, collection: 'matter_workflows' })
export class MatterWorkflow {
  @Prop({ required: true, index: true })
  matterId: string

  @Prop({ required: true, index: true })
  clientFolderId: string

  @Prop({ required: true })
  templateId: string

  @Prop({ required: true })
  templateName: string

  @Prop({ type: [Object], default: [] })
  steps: MatterWorkflowStep[]

  @Prop({ default: 'active', enum: ['active', 'completed', 'archived'] })
  status: string

  @Prop()
  instantiatedBy?: string

  @Prop()
  completedAt?: Date

  @Prop()
  notes?: string
}

export const MatterWorkflowSchema = SchemaFactory.createForClass(MatterWorkflow)
export type MatterWorkflowDocument = MatterWorkflow & Document

// ─── LawCorpusEntry ────────────────────────────────────────────────────────
// Stores laws, circulars, regulations, and policy updates retrieved by the
// RAG Agent. Not tied to any single client — this is the firm's law library.

export type LawDocType = 'statute' | 'circular' | 'regulation' | 'amendment' | 'policy_update' | 'gazette' | 'other'

@Schema({ timestamps: true, collection: 'law_corpus' })
export class LawCorpusEntry {
  @Prop({ required: true })
  title: string                     // official title (Thai or English)

  @Prop()
  titleLocal?: string               // Thai title if primary is English

  @Prop({ required: true, enum: ['statute', 'circular', 'regulation', 'amendment', 'policy_update', 'gazette', 'other'] })
  lawType: LawDocType

  @Prop({ required: true })
  practiceArea: string              // immigration | corporate | property | etc.

  @Prop({ default: 'th' })
  jurisdiction: string              // 'th' | 'th-boi' | 'th-doe' etc.

  @Prop({ required: true })
  sourceUrl: string                 // where it was retrieved from

  @Prop()
  storageKey?: string               // path under uploads/law-corpus/ (if downloaded)

  @Prop({ enum: ['en', 'th', 'bilingual'], default: 'th' })
  language: string

  @Prop()
  summary?: string                  // AI-generated summary (populated later)

  @Prop()
  effectiveDate?: Date              // date the law comes/came into effect

  @Prop()
  issuedBy?: string                 // issuing authority (e.g. "Immigration Bureau")

  @Prop()
  referenceCode?: string            // official reference number / section

  @Prop({ type: [String], default: [] })
  tags: string[]                    // keywords for lookup

  @Prop({ type: [String], default: [] })
  relatedMatterIds: string[]        // matters this was retrieved for

  @Prop()
  retrievedBy?: string              // 'rag-agent' or userId
}

export const LawCorpusEntrySchema = SchemaFactory.createForClass(LawCorpusEntry)
export type LawCorpusEntryDocument = LawCorpusEntry & Document

// ─── ObligationRule ───────────────────────────────────────────────────────────
// Structured timing rules stored by the RAG Agent and manually by the legal team.
// The Client Manager agent reads these to forecast MatterDeadline proposals.
// Generic — no hardcoded logic. Rules drive everything.

@Schema({ timestamps: true, collection: 'obligation_rules' })
export class ObligationRule {
  @Prop({ required: true })
  obligationKey: string             // stable identifier e.g. "tm47_90day_report"

  @Prop({ required: true })
  name: string                      // "90-Day Reporting Requirement (TM.47)"

  @Prop()
  description?: string

  @Prop({ required: true })
  practiceArea: string              // immigration | property | corporate | etc.

  @Prop({ type: [String], default: [] })
  matterSubTypes: string[]          // matches matter.subType — empty = applies to all in practiceArea

  @Prop({ default: 'th' })
  jurisdiction: string

  // ── Timing ───────────────────────────────────────────────────────────────
  @Prop({ required: true })
  anchorField: string               // "client.arrivalDate" | "client.visaExpiry" | "matter.openedDate" | "client.permitExpiry"

  @Prop({ default: 0 })
  offsetDays: number                // days from anchor: positive = after, negative = before

  @Prop()
  intervalDays?: number             // set for recurring obligations (e.g. 90 = every 90 days)

  @Prop()
  maxRecurrences?: number           // null/undefined = indefinite

  @Prop({ default: 14 })
  reminderLeadDays: number          // days before due date to trigger reminder

  // ── Linked resources ─────────────────────────────────────────────────────
  @Prop({ type: [String], default: [] })
  linkedFormIds: string[]           // FormTemplate _ids to attach to this obligation

  @Prop()
  sourceRef?: string                // LawCorpusEntry _id or citation that established this rule

  @Prop()
  notes?: string                    // internal notes for legal team

  @Prop({ default: true })
  isActive: boolean

  @Prop({ default: 'system' })
  createdBy: string
}

export const ObligationRuleSchema = SchemaFactory.createForClass(ObligationRule)
export type ObligationRuleDocument = ObligationRule & Document

// ─── MatterDeadline ───────────────────────────────────────────────────────────
// A single deadline instance generated for a specific matter.
// Status 'proposed' = awaiting attorney confirmation.
// Confirmed events are monitored by Client Manager → Case Analyst → Comms Agent.
// Every edit/rejection is a training signal for the fine-tuning pipeline.

export type DeadlineStatus = 'proposed' | 'confirmed' | 'rejected' | 'reminder_sent' | 'completed' | 'overdue'

@Schema({ timestamps: true, collection: 'matter_deadlines' })
export class MatterDeadline {
  @Prop({ type: Types.ObjectId, ref: 'Matter', required: true, index: true })
  matterId: Types.ObjectId

  @Prop({ type: Types.ObjectId, ref: 'ClientFolder', required: true, index: true })
  clientFolderId: Types.ObjectId

  @Prop({ type: Types.ObjectId, ref: 'ObligationRule' })
  obligationRuleId?: Types.ObjectId  // null if manually created

  @Prop({ required: true })
  obligationKey: string              // copied from rule for denormalisation

  @Prop({ required: true })
  name: string

  @Prop()
  description?: string

  // ── Timing ───────────────────────────────────────────────────────────────
  @Prop({ required: true })
  dueDate: Date

  @Prop()
  anchorDate?: Date                  // the actual date value used as anchor

  @Prop()
  anchorField?: string               // which field was used

  @Prop()
  intervalDays?: number              // populated for recurring

  @Prop({ default: 0 })
  recurrenceIndex: number            // 0 = first occurrence, 1 = second, etc.

  @Prop({ required: true })
  reminderDate: Date                 // dueDate minus reminderLeadDays

  // ── Linked resources ─────────────────────────────────────────────────────
  @Prop({ type: [String], default: [] })
  linkedFormIds: string[]

  // ── Confirmation workflow ─────────────────────────────────────────────────
  @Prop({ required: true, enum: ['proposed', 'confirmed', 'rejected', 'reminder_sent', 'completed', 'overdue'], default: 'proposed' })
  status: DeadlineStatus

  @Prop({ default: 'system' })
  proposedBy: string                 // 'system' | 'client_manager' | userId

  @Prop()
  confirmedBy?: string               // attorney userId

  @Prop()
  confirmedAt?: Date

  // ── Training signals ──────────────────────────────────────────────────────
  @Prop()
  rejectionReason?: string           // why attorney rejected — feeds fine-tuning

  @Prop({ type: Object })
  editDelta?: Record<string, { from: any; to: any }>  // what attorney changed before confirming

  @Prop()
  notes?: string
}

export const MatterDeadlineSchema = SchemaFactory.createForClass(MatterDeadline)
export type MatterDeadlineDocument = MatterDeadline & Document
