import { prisma } from '../lib/prisma'
import { LicenseStatus } from '@rentaldrivego/database'

const MS_PER_DAY = 1000 * 60 * 60 * 24

/** Minimum days of remaining validity required (configurable via env, default 30). */
function getMinValidityDays(): number {
  const raw = process.env.LICENSE_MIN_VALIDITY_DAYS
  if (raw) {
    const n = Number(raw)
    if (Number.isFinite(n) && n > 0) return n
  }
  return 30
}

/** Maximum years in the future considered reasonable for a license expiration date. */
const MAX_FUTURE_YEARS = 20

// ── Error codes matching doc/error-code reference ────────────────────────
export const ErrorCode = {
  LICENSE_EXPIRED:       'LICENSE_EXPIRED',
  LICENSE_EXPIRING_SOON: 'LICENSE_EXPIRING_SOON',
  LICENSE_INVALID_FORMAT:'LICENSE_INVALID_FORMAT',
  LICENSE_FUTURE_DATE:   'LICENSE_FUTURE_DATE',
  LICENSE_MISSING_DATE:  'LICENSE_MISSING_DATE',
} as const

export interface LicenseValidationResult {
  status: 'VALID' | 'EXPIRING' | 'EXPIRED'
  daysUntilExpiry: number | null
  requiresApproval: boolean
  message: string
}

export interface DetailedValidationResult {
  valid: boolean
  days_remaining: number | null
  expiration_date: string | null
  message: string
  error_code?: string
  details?: {
    expiration_date?: string
    days_remaining?: number
    minimum_required?: number
    suggested_action?: string
  }
}

/**
 * Parse an expiration date string into a Date.
 * Returns null if the string is not a valid date per ISO 8601 or common
 * US/EU formats (YYYY-MM-DD, MM/DD/YYYY, DD/MM/YYYY).
 */
export function parseExpirationDate(raw: string | null | undefined): Date | null {
  if (!raw) return null

  // Try ISO 8601 first (YYYY-MM-DD or full ISO)
  const iso = new Date(raw)
  if (!isNaN(iso.getTime()) && raw.length >= 10) {
    // Ensure we don't accept "2026-06" as valid — need at least YYYY-MM-DD
    const datePart = raw.split('T')[0]
    if (!datePart) return null
    const parts = datePart.split('-')
    if (parts.length === 3) return iso
  }

  // Try MM/DD/YYYY and DD/MM/YYYY
  const slashMatch = raw.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/)
  if (slashMatch) {
    // Prefer US order (MM/DD/YYYY) as default; document says "varies by state"
    const m1 = Number(slashMatch[1])
    const m2 = Number(slashMatch[2])
    const year = Number(slashMatch[3])
    // If first part > 12, it's likely DD/MM/YYYY
    if (m1 > 12) {
      const d = new Date(year, m2 - 1, m1)
      if (!isNaN(d.getTime())) return d
    }
    const d = new Date(year, m1 - 1, m2)
    if (!isNaN(d.getTime())) return d
  }

  // Try DD-MMM-YYYY (e.g., 11-JUN-2027)
  const mmmMatch = raw.match(/^(\d{1,2})-([A-Za-z]{3})-(\d{4})$/)
  if (mmmMatch) {
    const d = new Date(`${mmmMatch[2]} ${mmmMatch[1]}, ${mmmMatch[3]}`)
    if (!isNaN(d.getTime())) return d
  }

  return null
}

/**
 * Pure validation logic — no side effects, no DB calls.
 *
 * Returns a DetailedValidationResult suitable for the public API.
 */
export function validateLicenseDate(expirationDate: Date | null | undefined): DetailedValidationResult {
  if (!expirationDate) {
    return {
      valid: false,
      days_remaining: null,
      expiration_date: null,
      message: 'No expiration date provided. Please provide a valid driver\'s license expiration date.',
      error_code: ErrorCode.LICENSE_MISSING_DATE,
      details: {
        suggested_action: 'Please provide the expiration date from your driver\'s license.',
      },
    }
  }

  const now = new Date()
  const nowMs = now.getTime()
  const expMs = expirationDate.getTime()
  const daysRemaining = Math.ceil((expMs - nowMs) / MS_PER_DAY)
  const expDateStr = expirationDate.toISOString().split('T')[0] ?? ''
  const minValidityDays = getMinValidityDays()

  // Expired
  if (expMs <= nowMs) {
    return {
      valid: false,
      days_remaining: daysRemaining,
      expiration_date: expDateStr,
      message: `License has expired. Your license expired on ${expDateStr}.`,
      error_code: ErrorCode.LICENSE_EXPIRED,
      details: {
        expiration_date: expDateStr,
        days_remaining: daysRemaining,
        minimum_required: minValidityDays,
        suggested_action: 'Please renew your driver\'s license and upload the updated document.',
      },
    }
  }

  // Expiring soon (1 – minValidityDays-1 days remaining)
  if (daysRemaining < minValidityDays) {
    return {
      valid: false,
      days_remaining: daysRemaining,
      expiration_date: expDateStr,
      message: `License must have at least ${minValidityDays} days remaining validity. Your license expires in ${daysRemaining} days on ${expDateStr}.`,
      error_code: ErrorCode.LICENSE_EXPIRING_SOON,
      details: {
        expiration_date: expDateStr,
        days_remaining: daysRemaining,
        minimum_required: minValidityDays,
        suggested_action: `Please upload a valid license with more than ${minValidityDays} days remaining.`,
      },
    }
  }

  // Future date (>MAX_FUTURE_YEARS from now)
  const maxFutureMs = nowMs + MAX_FUTURE_YEARS * 365 * MS_PER_DAY
  if (expMs > maxFutureMs) {
    return {
      valid: false,
      days_remaining: daysRemaining,
      expiration_date: expDateStr,
      message: `The provided expiration date (${expDateStr}) is too far in the future. Please verify the date is correct.`,
      error_code: ErrorCode.LICENSE_FUTURE_DATE,
      details: {
        expiration_date: expDateStr,
        days_remaining: daysRemaining,
        minimum_required: minValidityDays,
        suggested_action: 'Please check the expiration date on your license and re-enter it correctly.',
      },
    }
  }

  // Valid
  const nextReminder = new Date(expMs - minValidityDays * MS_PER_DAY).toISOString().split('T')[0]
  return {
    valid: true,
    days_remaining: daysRemaining,
    expiration_date: expDateStr,
    message: 'License verified successfully',
    details: {
      days_remaining: daysRemaining,
      minimum_required: minValidityDays,
      suggested_action: 'License is valid.',
    },
  }
}

/**
 * Legacy validation function used internally by the customer service.
 * Returns a simpler result compatible with existing callers.
 */
export function validateLicense(licenseExpiry: Date | null): LicenseValidationResult {
  if (!licenseExpiry) {
    return { status: 'VALID', daysUntilExpiry: null, requiresApproval: false, message: 'No expiry date on record' }
  }

  const now = new Date()
  const daysUntilExpiry = Math.ceil((licenseExpiry.getTime() - now.getTime()) / MS_PER_DAY)
  const minValidityDays = getMinValidityDays()
  const minValidityMs = minValidityDays * MS_PER_DAY

  if (licenseExpiry <= now) {
    return { status: 'EXPIRED', daysUntilExpiry, requiresApproval: true, message: `License expired ${Math.abs(daysUntilExpiry)} day(s) ago` }
  }

  if (licenseExpiry.getTime() - now.getTime() < minValidityMs) {
    return { status: 'EXPIRING', daysUntilExpiry, requiresApproval: true, message: `License expires in ${daysUntilExpiry} day(s) — approval required` }
  }

  return { status: 'VALID', daysUntilExpiry, requiresApproval: false, message: `Valid — expires in ${daysUntilExpiry} day(s)` }
}

export async function validateAndFlagLicense(customerId: string, companyId?: string) {
  const where = companyId ? { id: customerId, companyId } : { id: customerId }
  const customer = await prisma.customer.findFirstOrThrow({ where })
  const result = validateLicense(customer.licenseExpiry)

  const status: LicenseStatus =
    result.status === 'EXPIRED' ? 'EXPIRED' :
    result.status === 'EXPIRING' ? 'EXPIRING' : 'VALID'

  if (companyId) {
    await prisma.customer.updateMany({
      where: { id: customerId, companyId },
      data: {
        licenseExpired:          result.status === 'EXPIRED',
        licenseExpiringSoon:     result.status === 'EXPIRING',
        licenseValidationStatus: status,
        flagged:                 result.requiresApproval ? true : customer.flagged,
        flagReason:              result.requiresApproval ? result.message : customer.flagReason,
      },
    })
  } else {
    await prisma.customer.update({
      where: { id: customerId },
      data: {
        licenseExpired:          result.status === 'EXPIRED',
        licenseExpiringSoon:     result.status === 'EXPIRING',
        licenseValidationStatus: status,
        flagged:                 result.requiresApproval ? true : customer.flagged,
        flagReason:              result.requiresApproval ? result.message : customer.flagReason,
      },
    })
  }

  return result
}
