import { validateAndFlagLicense } from '../../services/licenseValidationService'
import { uploadImage, deleteImage, resolveStoredFilePath } from '../../lib/storage'
import { NotFoundError } from '../../http/errors'
import { presentCustomer, presentCustomerList } from './customer.presenter'
import * as repo from './customer.repo'

export async function listCustomers(companyId: string, query: { page?: number; pageSize?: number; q?: string; flagged?: string }) {
  const page     = query.page     ?? 1
  const pageSize = query.pageSize ?? 20
  const { q, flagged } = query
  const safeQ = q ? q.trim().slice(0, 100) : undefined
  const where: any = { companyId }
  if (flagged !== undefined) where.flagged = flagged === 'true'
  if (safeQ) {
    where.OR = [
      { firstName: { contains: safeQ, mode: 'insensitive' } },
      { lastName:  { contains: safeQ, mode: 'insensitive' } },
      { email:     { contains: safeQ, mode: 'insensitive' } },
    ]
  }
  const [customers, total] = await repo.findMany(where, (page - 1) * pageSize, pageSize)
  return presentCustomerList(customers.map(presentCustomer), { total, page, pageSize, totalPages: Math.ceil(total / pageSize) })
}

export async function getCustomer(id: string, companyId: string) {
  const customer = await repo.findById(id, companyId)
  if (!customer) throw new NotFoundError('Customer not found')
  return presentCustomer(customer)
}

export async function createCustomer(data: any, companyId: string) {
  const customer = await repo.create({
    ...data,
    companyId,
    dateOfBirth:     data.dateOfBirth     ? new Date(data.dateOfBirth)     : null,
    licenseExpiry:   data.licenseExpiry   ? new Date(data.licenseExpiry)   : null,
    licenseIssuedAt: data.licenseIssuedAt ? new Date(data.licenseIssuedAt) : null,
  })
  if (data.licenseExpiry) {
    await validateAndFlagLicense(customer.id, companyId).catch(() => null)
  }
  return presentCustomer(customer)
}

export async function updateCustomer(id: string, companyId: string, data: any) {
  const result = await repo.updateMany(id, companyId, {
    ...data,
    dateOfBirth:     data.dateOfBirth     ? new Date(data.dateOfBirth)     : undefined,
    licenseExpiry:   data.licenseExpiry   ? new Date(data.licenseExpiry)   : undefined,
    licenseIssuedAt: data.licenseIssuedAt ? new Date(data.licenseIssuedAt) : undefined,
  })
  if (result.count === 0) throw new NotFoundError('Customer not found')
  if (data.licenseExpiry) await validateAndFlagLicense(id, companyId).catch(() => null)
  return presentCustomer(await repo.findUniqueOrThrow(id, companyId))
}

export async function flagCustomer(id: string, companyId: string, reason?: string) {
  await repo.updateMany(id, companyId, { flagged: true, flagReason: reason ?? null })
}

export async function unflagCustomer(id: string, companyId: string) {
  await repo.updateMany(id, companyId, { flagged: false, flagReason: null })
}

export async function validateCustomerLicense(id: string, companyId: string) {
  const customer = await repo.findByIdSimple(id, companyId)
  if (!customer) throw new NotFoundError('Customer not found')
  return validateAndFlagLicense(customer.id, companyId)
}

export async function uploadLicenseImage(id: string, companyId: string, file: Express.Multer.File) {
  const customer = await repo.findByIdSimple(id, companyId)
  if (!customer) throw new NotFoundError('Customer not found')
  const url = await uploadImage(file.buffer, `companies/${companyId}/customers/${customer.id}`)
  if (customer.licenseImageUrl) {
    await deleteImage(customer.licenseImageUrl).catch(() => null)
  }
  return presentCustomer(await repo.updateById(customer.id, { licenseImageUrl: url }))
}

export async function getLicenseImageFile(id: string, companyId: string) {
  const customer = await repo.findByIdSimple(id, companyId)
  if (!customer || !customer.licenseImageUrl) throw new NotFoundError('License image not found')

  const filePath = resolveStoredFilePath(customer.licenseImageUrl)
  if (!filePath) throw new NotFoundError('License image not found')

  return filePath
}

export async function approveLicense(id: string, companyId: string, decision: 'APPROVE' | 'DENY', note: string | undefined, approverName: string) {
  const customer = await repo.findByIdSimple(id, companyId)
  if (!customer) throw new NotFoundError('Customer not found')
  return presentCustomer(await repo.updateById(customer.id, {
    licenseValidationStatus: decision === 'APPROVE' ? 'APPROVED' : 'DENIED',
    licenseApprovedBy:       approverName,
    licenseApprovedAt:       new Date(),
    licenseApprovalNote:     note ?? null,
  }))
}
