import { Injectable, NotFoundException } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { Model } from 'mongoose'
import { ClientFolder, ClientFolderDocument, RetainerTransaction } from '../common/schemas'
import { CreateTransactionDto } from './dto/create-transaction.dto'
import { TrustService } from '../trust/trust.service'

const POSITIVE_TYPES = new Set(['intake'])

// Map retainer transaction type → trust transaction type
const TRUST_TYPE_MAP: Record<string, string> = {
  intake:           'receipt',
  disbursement:     'fee_draw',
  invoice_applied:  'fee_draw',
  refund:           'refund',
}

@Injectable()
export class RetainerService {
  constructor(
    @InjectModel(ClientFolder.name) private folderModel: Model<ClientFolderDocument>,
    private readonly trustService: TrustService,
  ) {}

  async getLedger(clientFolderId: string) {
    const folder = await this.folderModel.findById(clientFolderId).exec()
    if (!folder) throw new NotFoundException(`Client folder ${clientFolderId} not found`)
    return {
      balance: folder.retainerBalance ?? 0,
      currency: folder.currency ?? 'THB',
      threshold: folder.retainerThreshold ?? 0,
      transactions: folder.retainerLedger ?? [],
    }
  }

  async addTransaction(clientFolderId: string, dto: CreateTransactionDto): Promise<ClientFolderDocument> {
    const folder = await this.folderModel.findById(clientFolderId).exec()
    if (!folder) throw new NotFoundException(`Client folder ${clientFolderId} not found`)

    const isPositive = POSITIVE_TYPES.has(dto.type)
    const signedAmount = isPositive ? Math.abs(dto.amount) : -Math.abs(dto.amount)

    const tx: RetainerTransaction = {
      txId: `TX-${Date.now()}`,
      type: dto.type,
      amount: signedAmount,
      currency: folder.currency ?? 'THB',
      date: dto.date ? new Date(dto.date) : new Date(),
      description: dto.description ?? '',
      invoiceRef: dto.invoiceRef,
      matterId: dto.matterId,
      createdBy: dto.createdBy ?? 'system',
    }

    const updated = await this.folderModel.findByIdAndUpdate(
      clientFolderId,
      {
        $inc: { retainerBalance: signedAmount },
        $push: { retainerLedger: tx },
      },
      { new: true },
    ).exec() as ClientFolderDocument

    // Mirror into trust ledger so both are always in sync
    const trustType = TRUST_TYPE_MAP[dto.type]
    if (trustType) {
      await this.trustService.addTransaction({
        clientFolderId,
        matterId:    dto.matterId,
        txDate:      tx.date.toISOString(),
        type:        trustType,
        amount:      Math.abs(dto.amount),
        currency:    folder.currency ?? 'THB',
        description: dto.description ?? `Retainer ${dto.type}`,
        reference:   dto.invoiceRef,
        createdBy:   dto.createdBy ?? 'system',
      })
    }

    return updated
  }

  async checkLowBalance(clientFolderId: string) {
    const { balance, threshold } = await this.getLedger(clientFolderId)
    return { low: threshold > 0 && balance < threshold, balance, threshold }
  }
}
