// Browser-side Universal Design → Cover adaptation engine.
// Produces an HONEST visual adaptation preview from cover region metadata.
// It never claims final geometric fit — that is the Geometry Engine's job.
//
// All positions/scales here are NORMALISED (0..1) cover-relative values,
// independent of any one cover's millimetre coordinates, so the same
// Universal Design can be re-fitted to many covers without distortion
// of the stored master.

// Default decoration rect (normalised) used when a cover has no zone metadata.
const DEFAULT_DECORATION_RECT = { x: 0.16, y: 0.2, w: 0.68, h: 0.58 };

// Map a semantic placement intent to a normalised anchor point.
const PLACEMENT_ANCHORS = {
  front_centre: { u: 0.5, v: 0.5 },
  upper_front: { u: 0.5, v: 0.3 },
  lower_front: { u: 0.5, v: 0.72 },
  outer_side: { u: 0.78, v: 0.5 },
  inner_side: { u: 0.22, v: 0.5 },
  rear: { u: 0.5, v: 0.85 },
  wrap_around: { u: 0.5, v: 0.5 },
  full_surface: { u: 0.5, v: 0.5 },
  border_following: { u: 0.5, v: 0.5 },
  along_length: { u: 0.5, v: 0.5 },
  around_widest: { u: 0.5, v: 0.55 },
  let_shire_choose: { u: 0.5, v: 0.5 }
};

const STRATEGIES = {
  best_fit: { scale: 0.82, preserveAspect: true, fill: false, label: 'Recommended fit' },
  front_feature: { scale: 0.7, preserveAspect: true, fill: false, anchor: 'front_centre', label: 'Front feature' },
  side_feature: { scale: 0.7, preserveAspect: true, fill: false, anchor: 'outer_side', label: 'Side feature' },
  full_wrap: { scale: 0.95, preserveAspect: false, fill: true, label: 'Full wrap' },
  panel_fit: { scale: 0.8, preserveAspect: true, fill: false, label: 'Panel fit' },
  symmetrical_fit: { scale: 0.8, preserveAspect: true, fill: false, mirror: true, label: 'Symmetrical fit' },
  minimal_distortion: { scale: 0.6, preserveAspect: true, fill: false, label: 'Keep original shape' },
  maximum_coverage: { scale: 0.98, preserveAspect: false, fill: true, label: 'Fill cover' }
};

export const ADAPTATION_STRATEGIES = STRATEGIES;

function safeArr(x) { return Array.isArray(x) ? x : []; }

// Derive a normalised decoration rect from cover zone metadata if present.
export function decorationRect(cover) {
  const zones = safeArr(cover?.decorationZones);
  if (!zones.length) return { ...DEFAULT_DECORATION_RECT, inferred: true };
  // Use the first zone's normalised bounds if provided; otherwise default.
  const z = zones[0] || {};
  if (typeof z.u === 'number' && typeof z.v === 'number') {
    return { x: z.u, y: z.v, w: z.w ?? 0.68, h: z.h ?? 0.58, inferred: false };
  }
  return { ...DEFAULT_DECORATION_RECT, inferred: false };
}

// Browser-level compatibility analysis from metadata only. Never claims
// geometric certainty.
export function analyseCoverCompatibility({ design, cover, geometryAvailable = false }) {
  const reasons = [];
  let level = 'good';
  if (!cover) { return { level: 'requires_processing', reasons: ['No cover selected.'] }; }
  if (!cover.previewImageUrl && !cover.previewModelUrl) { reasons.push('Cover has no preview model.'); level = 'limited'; }
  if (!safeArr(cover.decorationZones).length) { reasons.push('Decoration-zone metadata is missing — placement is estimated.'); level = level === 'good' ? 'adaptable' : level; }
  if (!safeArr(cover.protectedZones).length) { reasons.push('Protected-zone metadata is missing — safety checks deferred to the Geometry Engine.'); }
  if (!safeArr(cover.brandingZones).length) { reasons.push('Branding-zone metadata is missing.'); }
  if (!cover.limbType || !cover.side) { reasons.push('Target limb / side not specified.'); level = 'limited'; }
  if (design?.intendedApplicationMode === 'stencil' && !safeArr(cover.decorationZones).length) {
    reasons.push('Cut-out designs need explicit decoration zones.'); level = 'limited';
  }
  // Browser metadata can never confirm final geometry.
  reasons.push('Final surface fitting requires the LimbForge Geometry Engine.');
  if (level === 'good' && !geometryAvailable) level = 'adaptable';
  if (!geometryAvailable && level === 'good') level = 'requires_processing';
  return { level, reasons };
}

// Compute the adapted placement of each design layer in normalised cover space.
// Returns per-layer transforms + an honest summary of what was adjusted.
export function computeAdaptation({ design, layers = [], cover, strategy = 'best_fit', mirror = 'none' }) {
  const strat = STRATEGIES[strategy] || STRATEGIES.best_fit;
  const rect = decorationRect(cover);
  const intent = design?.placementIntent || 'let_shire_choose';
  const anchor = PLACEMENT_ANCHORS[strat.anchor || intent] || PLACEMENT_ANCHORS.let_shire_choose;

  const safeLayers = safeArr(layers).filter(l => l.visible !== false).sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
  const primary = safeLayers.find(l => l.role === 'primary_emblem') || safeLayers[0];

  const adapted = safeLayers.map((l, i) => {
    const isPrimary = l === primary;
    const focal = isPrimary;
    // Primary follows the strategy anchor; secondary pieces spread around it.
    let u = anchor.u, v = anchor.v;
    if (!isPrimary) {
      const spread = 0.16 * (i - (safeLayers.length - 1) / 2);
      u = anchor.u + spread;
      v = anchor.v + 0.18 * ((i % 2) ? 1 : -1);
      u = Math.min(0.92, Math.max(0.08, u));
      v = Math.min(0.92, Math.max(0.08, v));
    }
    let scale = strat.scale;
    if (isPrimary && strat.preserveAspect) scale = Math.min(scale, 0.7);
    if (l.aspectPolicy === 'keep_shape' || l.protectedFromDistortion) scale = Math.min(scale, 0.6);

    const repeatable = (l.mayRepeat || l.aspectPolicy === 'repeatable') && strat.fill;
    const clipped = strat.fill && !l.protectedFromDistortion && (l.mayClip || l.aspectPolicy === 'croppable');
    const mirrored = mirror === 'mirror' || (mirror === 'smart' && !l.protectedFromDistortion && l.aspectPolicy !== 'keep_shape');

    return {
      layerId: l.id || `layer-${i}`,
      name: l.name,
      role: l.role,
      focal,
      positionU: u,
      positionV: v,
      scale,
      relativeWidth: strat.fill ? rect.w : scale * rect.w,
      relativeHeight: strat.fill ? rect.h : scale * rect.h,
      rotation: l.relativeRotation || 0,
      mirrored,
      repeated: repeatable,
      clipped,
      protectedFromDistortion: !!l.protectedFromDistortion,
      applicationIntent: l.applicationIntent || design?.intendedApplicationMode || 'colour_texture'
    };
  });

  // Protected-zone warnings: focal pieces must avoid protected regions.
  const protectedZones = safeArr(cover?.protectedZones);
  const protectedZoneWarnings = [];
  if (protectedZones.length && primary) {
    // Heuristic: if focal anchor lands near edges where protected zones usually sit, warn.
    if (anchor.u > 0.85 || anchor.u < 0.15) {
      protectedZoneWarnings.push('Main design is close to a protected edge — the Geometry Engine will confirm clearance.');
    }
  }

  const moved = adapted.filter(a => !a.focal && (a.repeated || a.clipped)).length;
  const summary = moved
    ? `We adjusted ${moved} design ${moved === 1 ? 'piece' : 'pieces'} to fit this cover safely.`
    : 'Your design fits within the safe decoration area for this cover.';

  const details = [];
  if (primary) details.push(`${primary.name || 'Main emblem'} preserved`);
  if (adapted.some(a => a.repeated)) details.push('Background pattern repeated');
  if (adapted.some(a => a.clipped)) details.push('Edge pieces cropped at the decoration boundary');
  if (adapted.some(a => a.mirrored)) details.push('Decorative pieces mirrored for this side');
  if (protectedZoneWarnings.length) details.push(protectedZoneWarnings[0]);

  return {
    strategy,
    decorationRect: rect,
    anchor,
    adaptedLayers: adapted,
    focalPointResults: { primaryPreserved: !!primary, anchor },
    distortionReport: { preserveAspect: strat.preserveAspect, maxScale: strat.scale, fill: strat.fill },
    clippedRegions: adapted.filter(a => a.clipped).map(a => ({ layer: a.name })),
    repeatedRegions: adapted.filter(a => a.repeated).map(a => ({ layer: a.name })),
    movedRegions: adapted.filter(a => !a.focal).map(a => ({ layer: a.name })),
    protectedZoneWarnings,
    brandingStatus: safeArr(cover?.brandingZones).length ? 'preserved' : 'unverified',
    summary,
    details,
    simulation: true,
    note: 'Browser preview only. Final surface wrapping and print checks happen during 3D processing.'
  };
}

// Strategy options with friendly guided labels.
export const GUIDED_STRATEGY_CHOICES = [
  ['best_fit', 'Recommended fit'],
  ['front_feature', 'Front'],
  ['side_feature', 'Side'],
  ['full_wrap', 'Wrap'],
  ['maximum_coverage', 'Fill cover'],
  ['minimal_distortion', 'Keep original shape']
];

export const PLACEMENT_CHOICES = [
  ['front_centre', 'Front centre'],
  ['upper_front', 'Upper front'],
  ['lower_front', 'Lower front'],
  ['outer_side', 'Outer side'],
  ['inner_side', 'Inner side'],
  ['rear', 'Rear'],
  ['wrap_around', 'Wrap around'],
  ['full_surface', 'Full surface pattern'],
  ['border_following', 'Border-following'],
  ['along_length', 'Along cover length'],
  ['around_widest', 'Around widest area'],
  ['let_shire_choose', 'Let SHiRE choose']
];

export const CHARACTER_CHOICES = ['Clean', 'Bold', 'Futuristic', 'Mechanical', 'Organic', 'Gothic', 'Playful', 'Minimal', 'Detailed'];

export const INTENDED_RESULTS = [
  ['colour_texture', 'Colour design', 'Primarily visual surface artwork.'],
  ['raised_emboss', 'Raised design', 'Intended to stand above the cover.'],
  ['engraving', 'Engraved design', 'Intended to sit below the surface.'],
  ['stencil', 'Cut-out design', 'Intended to create safe openings.'],
  ['sculpted_relief', 'Sculpted design', 'Intended to become deeper shaped geometry.'],
  ['mixed', 'Mixed design', 'Different effects for different pieces.']
];

export const DISTORTION_LABELS = {
  keep_shape: 'Keep shape',
  flexible: 'Fit gently',
  repeatable: 'Repeat pattern',
  croppable: 'Fill the cover',
  reflowable: 'Reflow',
  border_following: 'Follow border',
  full_wrap: 'Full wrap'
};