import { prisma } from '../../lib/prisma'

let customerLicenseImageColumnSupported: boolean | null = null

async function hasCustomerLicenseImageColumn() {
  if (customerLicenseImageColumnSupported !== null) {
    return customerLicenseImageColumnSupported
  }

  const rows = await prisma.$queryRawUnsafe<Array<{ exists: boolean }>>(
    "select exists(select 1 from information_schema.columns where table_schema = 'public' and table_name = 'customers' and column_name = 'licenseImageUrl') as exists"
  )
  customerLicenseImageColumnSupported = Boolean(rows[0]?.exists)
  return customerLicenseImageColumnSupported
}

function buildCustomerSelect(includeLicenseImageUrl: boolean) {
  return {
    id: true,
    companyId: true,
    renterId: true,
    firstName: true,
    lastName: true,
    email: true,
    phone: true,
    driverLicense: true,
    dateOfBirth: true,
    nationality: true,
    address: true,
    notes: true,
    flagged: true,
    flagReason: true,
    licenseExpiry: true,
    licenseIssuedAt: true,
    licenseCountry: true,
    licenseNumber: true,
    licenseCategory: true,
    licenseExpired: true,
    licenseExpiringSoon: true,
    licenseValidationStatus: true,
    licenseApprovedBy: true,
    licenseApprovedAt: true,
    licenseApprovalNote: true,
    ...(includeLicenseImageUrl ? { licenseImageUrl: true } : {}),
    createdAt: true,
    updatedAt: true,
  }
}

async function getCustomerSelect() {
  return buildCustomerSelect(await hasCustomerLicenseImageColumn())
}

async function sanitizeCustomerData(data: Record<string, unknown>) {
  if (await hasCustomerLicenseImageColumn()) {
    return data
  }

  const { licenseImageUrl, ...rest } = data
  void licenseImageUrl
  return rest as Record<string, unknown>
}

export async function findMany(where: any, skip: number, take: number) {
  const select = await getCustomerSelect()
  return Promise.all([
    prisma.customer.findMany({ where, skip, take, orderBy: { createdAt: 'desc' }, select }),
    prisma.customer.count({ where }),
  ])
}

export async function findById(id: string, companyId: string) {
  const select = await getCustomerSelect()
  return prisma.customer.findFirst({
    where: { id, companyId },
    select: {
      ...select,
      reservations: { include: { vehicle: true }, orderBy: { createdAt: 'desc' }, take: 20 },
    },
  })
}

export async function findByIdSimple(id: string, companyId: string) {
  return prisma.customer.findFirst({ where: { id, companyId }, select: await getCustomerSelect() })
}

export async function create(data: any) {
  return prisma.customer.create({ data: (await sanitizeCustomerData(data)) as any, select: await getCustomerSelect() })
}

export async function updateMany(id: string, companyId: string, data: any) {
  return prisma.customer.updateMany({ where: { id, companyId }, data })
}

export async function updateById(id: string, data: any) {
  return prisma.customer.update({
    where: { id },
    data: (await sanitizeCustomerData(data)) as any,
    select: await getCustomerSelect(),
  })
}

export async function findUniqueOrThrow(id: string, companyId?: string) {
  const select = await getCustomerSelect()
  if (companyId) {
    return prisma.customer.findFirstOrThrow({ where: { id, companyId }, select })
  }
  return prisma.customer.findUniqueOrThrow({ where: { id }, select })
}
