/**
 * Optical Calculation Utilities
 * Provides common calculations for optical prescriptions and lens measurements
 */

export interface TransposedResult {
  sphere: number
  cylinder: number
  axis: number
}

export interface GlassBaseResult {
  odBase: number
  ogBase: number
  recommendedBase: number
  notes: string
}

/**
 * Transpose cylinder to opposite sign
 * Used when converting between plus and minus cylinder notation
 *
 * @param sphere - The sphere power
 * @param cylinder - The cylinder power
 * @param axis - The axis in degrees (0-180)
 * @returns Transposed prescription with opposite cylinder sign
 */
export function transposeCylinder(
  sphere: number,
  cylinder: number,
  axis: number
): TransposedResult {
  // In transposition:
  // 1. New sphere = sphere + cylinder
  // 2. New cylinder = -cylinder
  // 3. New axis = axis + 90 (if > 180, subtract 180)

  const newSphere = parseFloat((sphere + cylinder).toFixed(2))
  const newCylinder = parseFloat((-cylinder).toFixed(2))
  const newAxis = (axis + 90) % 180

  return {
    sphere: newSphere,
    cylinder: newCylinder,
    axis: newAxis
  }
}

/**
 * Calculate minimum glass diameter based on prescription
 * This is a simplified calculation - actual requirements depend on frame measurements
 *
 * @param odSphere - Right eye sphere power
 * @param odCylindre - Right eye cylinder power
 * @param ogSphere - Left eye sphere power
 * @param ogCylindre - Left eye cylinder power
 * @returns Recommended minimum glass diameter for each eye
 */
export function calculateGlassBase(
  odSphere: number,
  odCylindre: number,
  ogSphere: number,
  ogCylindre: number
): GlassBaseResult {
  // Calculate absolute total power for each eye
  const odPower = Math.abs(odSphere + odCylindre)
  const ogPower = Math.abs(ogSphere + ogCylindre)

  // Base diameter calculation (simplified formula)
  // Higher powers require larger diameters to minimize edge thickness
  const calculateBaseDiameter = (power: number): number => {
    if (power <= 2.0) return 50
    if (power <= 4.0) return 52
    if (power <= 6.0) return 54
    if (power <= 8.0) return 56
    if (power <= 10.0) return 58
    return 60
  }

  const odBase = calculateBaseDiameter(odPower)
  const ogBase = calculateBaseDiameter(ogPower)
  const recommendedBase = Math.max(odBase, ogBase)

  let notes = ''
  if (odPower > 6.0 || ogPower > 6.0) {
    notes = 'Prescription forte - considérer verres à indice élevé pour réduire l\'épaisseur'
  } else if (Math.abs(odPower - ogPower) > 2.0) {
    notes = 'Anisométropie significative - attention aux effets prismatiques'
  }

  return {
    odBase,
    ogBase,
    recommendedBase,
    notes
  }
}

/**
 * Calculate spherical equivalent
 * Useful for estimating visual acuity and for certain lens types
 *
 * @param sphere - The sphere power
 * @param cylinder - The cylinder power
 * @returns Spherical equivalent value
 */
export function calculateSphericalEquivalent(
  sphere: number,
  cylinder: number
): number {
  return parseFloat((sphere + cylinder / 2).toFixed(2))
}

/**
 * Validate axis value (must be 0-180)
 *
 * @param axis - The axis in degrees
 * @returns True if axis is valid
 */
export function validateAxis(axis: number): boolean {
  return axis >= 0 && axis <= 180 && Number.isInteger(axis)
}

/**
 * Format prescription for display
 *
 * @param sphere - The sphere power
 * @param cylinder - The cylinder power
 * @param axis - The axis in degrees
 * @returns Formatted prescription string
 */
export function formatPrescription(
  sphere: number,
  cylinder: number,
  axis: number
): string {
  const sph = sphere.toFixed(2).replace(/\.00$/, '')
  const cyl = cylinder.toFixed(2).replace(/\.00$/, '')
  const ax = axis.toString()

  return `${sph} ${cyl >= 0 ? '+' : ''}${cyl} ax${ax}`
}

/**
 * Calculate total magnification (simplified)
 *
 * @param sphere - The sphere power
 * @param centerThickness - Center thickness in mm
 * @param vertexDistance - Vertex distance in mm (default 12mm)
 * @returns Magnification factor
 */
export function calculateMagnification(
  sphere: number,
  centerThickness: number,
  vertexDistance: number = 12
): number {
  // Simplified magnification formula
  const power = Math.abs(sphere)
  const magnification = 1 + (power * centerThickness) / 1000
  return parseFloat(magnification.toFixed(3))
}

/**
 * Determine recommended lens index based on prescription
 *
 * @param sphere - The sphere power
 * @param cylinder - The cylinder power
 * @returns Recommended refractive index
 */
export function getRecommendedIndex(
  sphere: number,
  cylinder: number
): number {
  const power = Math.abs(sphere + cylinder)

  if (power <= 2.0) return 1.5
  if (power <= 4.0) return 1.56
  if (power <= 6.0) return 1.6
  if (power <= 8.0) return 1.67
  return 1.74
}

/**
 * Check if prescription is within standard range
 *
 * @param sphere - The sphere power
 * @param cylinder - The cylinder power
 * @returns Object with validity status and reasons
 */
export function validatePrescription(
  sphere: number,
  cylinder: number
): { valid: boolean; reasons: string[] } {
  const reasons: string[] = []

  if (sphere < -20 || sphere > 20) {
    reasons.push('Sphère hors plage standard (-20 à +20)')
  }

  if (cylinder < -6 || cylinder > 6) {
    reasons.push('Cylindre hors plage standard (-6 à +6)')
  }

  return {
    valid: reasons.length === 0,
    reasons
  }
}
