import { Injectable, Logger } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { Model, Types } from 'mongoose'
import {
  ClientFolder, ClientFolderDocument,
  Matter, MatterDocument,
} from '../common/schemas'
import { MigrateImportDto, MigrateClientRow, MigrateMatterRow } from './dto/migrate.dto'

const DEFAULT_DOC_FOLDERS = [
  { name: 'Correspondence', icon: 'ri-mail-line',      color: '#4A90D9' },
  { name: 'Contracts',      icon: 'ri-file-text-line', color: '#7B68EE' },
  { name: 'Court Filings',  icon: 'ri-scales-line',    color: '#E8533A' },
  { name: 'Identity',       icon: 'ri-user-line',      color: '#2ECC71' },
  { name: 'Financial',      icon: 'ri-bank-line',      color: '#F39C12' },
  { name: 'Misc',           icon: 'ri-folder-line',    color: '#95A5A6' },
]

const PRACTICE_AREA_MAP: Record<string, string> = {
  immigration: 'immigration', visa: 'immigration', 'work permit': 'immigration',
  'tm.7': 'immigration', tm7: 'immigration',
  corporate: 'corporate', boi: 'corporate', company: 'corporate', commercial: 'corporate',
  civil: 'civil_litigation', 'civil litigation': 'civil_litigation', litigation: 'civil_litigation',
  property: 'property', 'real estate': 'property', land: 'property',
  family: 'family', divorce: 'family',
  employment: 'employment', labour: 'employment', labor: 'employment',
  criminal: 'criminal',
  // Thai
  'คดีแพ่ง': 'civil_litigation', 'คดีอาญา': 'criminal',
  'อสังหาริมทรัพย์': 'property', 'ครอบครัว': 'family',
  'แรงงาน': 'employment', 'บริษัท': 'corporate',
  'วีซ่า': 'immigration', 'ตรวจคนเข้าเมือง': 'immigration',
}

const CLIENT_STATUS_MAP: Record<string, string> = {
  active: 'active', open: 'active', current: 'active',
  closed: 'closed', inactive: 'closed',
  prospect: 'prospect', potential: 'prospect',
  rejected: 'rejected',
  'ลูกความ': 'active', 'ปิดแล้ว': 'closed', 'ผู้มุ่งหวัง': 'prospect',
}

const MATTER_STATUS_MAP: Record<string, string> = {
  open: 'open', active: 'open', pending: 'pending',
  closed: 'closed', complete: 'closed', completed: 'closed',
  archived: 'archived',
  'เปิด': 'open', 'ปิด': 'closed',
}

export interface MigrateResult {
  clientsImported: number
  clientsSkipped:  number
  mattersImported: number
  mattersSkipped:  number
  errors:          string[]
  warnings:        string[]
}

@Injectable()
export class MigrateService {
  private readonly logger = new Logger(MigrateService.name)

  constructor(
    @InjectModel(ClientFolder.name) private folderModel: Model<ClientFolderDocument>,
    @InjectModel(Matter.name)       private matterModel: Model<MatterDocument>,
  ) {}

  async import(dto: MigrateImportDto): Promise<MigrateResult> {
    const result: MigrateResult = {
      clientsImported: 0, clientsSkipped: 0,
      mattersImported: 0, mattersSkipped: 0,
      errors: [], warnings: [],
    }

    // externalId → MongoDB _id map for linking matters to clients
    const clientIdMap = new Map<string, string>()

    // ── 1. Import clients ────────────────────────────────────────────────────
    for (const row of dto.clients) {
      try {
        const folderId = await this.importClient(row, dto.defaultAttorney, result)
        if (folderId && row.externalId) {
          clientIdMap.set(row.externalId, folderId)
        }
      } catch (err: any) {
        result.errors.push(`Client "${row.companyName ?? row.lastName ?? row.externalId}": ${err.message}`)
      }
    }

    // ── 2. Import matters ────────────────────────────────────────────────────
    for (const row of dto.matters) {
      try {
        await this.importMatter(row, dto.defaultAttorney, clientIdMap, result)
      } catch (err: any) {
        result.errors.push(`Matter "${row.title ?? row.externalMatterId}": ${err.message}`)
      }
    }

    this.logger.log(
      `Migration complete — ${result.clientsImported} clients, ${result.mattersImported} matters imported`,
    )
    return result
  }

  private async importClient(
    row: MigrateClientRow,
    defaultAttorney: string,
    result: MigrateResult,
  ): Promise<string | null> {
    const displayName = this.deriveDisplayName(row)
    if (!displayName) {
      result.warnings.push(`Skipping client row — no name found: ${JSON.stringify(row)}`)
      result.clientsSkipped++
      return null
    }

    // Deduplicate by displayName (case-insensitive)
    const existing = await this.folderModel
      .findOne({ displayName: new RegExp(`^${displayName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'i') })
      .lean()
    if (existing) {
      result.warnings.push(`Skipping duplicate client: "${displayName}"`)
      result.clientsSkipped++
      return String(existing._id)
    }

    const folderNumber = await this.generateFolderNumber()
    const attorney = row.responsibleAttorney || defaultAttorney
    const now = new Date().toISOString()

    const clientType = this.detectClientType(row)

    const folder = await this.folderModel.create({
      folderNumber,
      clientType,
      displayName,
      firstName:  row.firstName,
      lastName:   row.lastName,
      companyName: clientType === 'corporate' ? (row.companyName || displayName) : undefined,
      email:      row.email,
      phone:      row.phone,
      address:    row.address,
      nationality: row.nationality,
      passportNumber: row.passportNumber,
      responsibleAttorney: attorney,
      originatingAttorney: row.originatingAttorney || attorney,
      status:     CLIENT_STATUS_MAP[row.status?.toLowerCase() ?? ''] ?? 'active',
      engagementDate: row.engagementDate ? new Date(row.engagementDate) : undefined,
      notes:      row.notes,
      retainerBalance: 0,
      retainerThreshold: 20000,
      currency: 'THB',
      batesCounter: 0,
      archived: false,
      docFolders: DEFAULT_DOC_FOLDERS.map(f => ({
        _id: new Types.ObjectId().toString(),
        name: f.name, icon: f.icon, color: f.color,
        isSystem: true, createdAt: now, createdBy: 'migration',
      })),
    })

    result.clientsImported++
    return String(folder._id)
  }

  private async importMatter(
    row: MigrateMatterRow,
    defaultAttorney: string,
    clientIdMap: Map<string, string>,
    result: MigrateResult,
  ): Promise<void> {
    if (!row.title) {
      result.warnings.push(`Skipping matter — no title: ${JSON.stringify(row)}`)
      result.mattersSkipped++
      return
    }

    // Resolve client folder
    const clientFolderId = row.externalClientId
      ? clientIdMap.get(row.externalClientId)
      : undefined

    if (!clientFolderId) {
      result.warnings.push(`Skipping matter "${row.title}" — client ID "${row.externalClientId}" not found in import`)
      result.mattersSkipped++
      return
    }

    const matterNumber = await this.generateMatterNumber(row.practiceArea)
    const attorney = row.responsibleAttorney || defaultAttorney

    const practiceArea = row.practiceArea
      ? (PRACTICE_AREA_MAP[row.practiceArea.toLowerCase()] ?? 'other')
      : 'other'

    const status = MATTER_STATUS_MAP[row.status?.toLowerCase() ?? ''] ?? 'open'

    await this.matterModel.create({
      matterNumber,
      clientFolderId: new Types.ObjectId(clientFolderId),
      title: row.title,
      practiceArea,
      subType: row.subType,
      status,
      responsibleAttorney: attorney,
      openedAt: row.openedAt ? new Date(row.openedAt) : new Date(),
      closedAt: row.closedAt ? new Date(row.closedAt) : undefined,
      notes: row.notes,
    })

    result.mattersImported++
  }

  // ── Helpers ───────────────────────────────────────────────────────────────

  private deriveDisplayName(row: MigrateClientRow): string {
    if (row.companyName) return row.companyName
    if (row.lastName && row.firstName) return `${row.lastName}, ${row.firstName}`
    if (row.lastName) return row.lastName
    if (row.firstName) return row.firstName
    return ''
  }

  private detectClientType(row: MigrateClientRow): 'individual' | 'corporate' {
    if (row.clientType) {
      const t = row.clientType.toLowerCase()
      if (['corporate', 'company', 'organisation', 'organization', 'บริษัท', 'นิติบุคคล'].includes(t))
        return 'corporate'
    }
    if (row.companyName && !row.firstName && !row.lastName) return 'corporate'
    return 'individual'
  }

  private async generateFolderNumber(): Promise<string> {
    const year = new Date().getFullYear()
    const count = await this.folderModel.countDocuments({ folderNumber: new RegExp(`^CF-${year}-`) })
    return `CF-${year}-${String(count + 1).padStart(4, '0')}`
  }

  private async generateMatterNumber(practiceArea?: string): Promise<string> {
    const year = new Date().getFullYear()
    const suffix = practiceArea
      ? (PRACTICE_AREA_MAP[practiceArea.toLowerCase()]?.slice(0, 3).toUpperCase() ?? 'GEN')
      : 'GEN'
    const count = await this.matterModel.countDocuments({ matterNumber: new RegExp(`^M-${year}-`) })
    return `M-${year}-${String(count + 1).padStart(4, '0')}-${suffix}`
  }
}
