// Mock data — re-creates the data shapes from data.jsx without hitting any API.
// Inspired by the real scoring logic in app.js / data.jsx.

const TORPEN_LOC = { lat: 47.7188, lon: -3.3727, name: "Anse Zanflamme" };

const BOAT = {
  name: "Torpen",
  model: "Elfe 8",
  builder: "Mecasoud (Guérande)",
  architect: "Bernard Veys",
  immat: "LO 681795",
  year: 1987,
  length_m: 7.99,
  beam_m: 4.02,
  draft_m: 0.70,
  weight_t: 1.35,
  sail_m2: 37,
  motor: "2 × Yamaha 15 ch",
  hull: "aluminium marin",
};

const THRESHOLDS = {
  windGo: 12, windCaution: 18,
  gustGo: 18, gustCaution: 25,
  waveGo: 0.8, waveCaution: 1.5,
  depthGo: 0.5, depthCaution: 0.2,
  visMinKm: 2,
  precipMax: 5,
  coefCaution: 95,
  coefNoGo: 105,
};

const DOWS = ['dim.','lun.','mar.','mer.','jeu.','ven.','sam.'];
const MONTHS = ['janv.','févr.','mars','avr.','mai','juin','juil.','août','sept.','oct.','nov.','déc.'];

function fmtTime(d) { return d.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' }); }

// Build 7 days of synthetic-but-plausible hourly data, anchored on May 7 2026.
function buildMockSeries() {
  const start = new Date('2026-05-07T00:00:00');
  const series = [];
  // Per-day archetype that drives the look of the day
  const dayArchetypes = [
    { label: "GO clean — light SE breeze",   wind: 7,  gust: 13, wave: 0.25, coef: 51, sky: 'sunny',    rain: 0   },
    { label: "GO morning, breeze afternoon", wind: 10, gust: 17, wave: 0.40, coef: 45, sky: 'cloudy',   rain: 0   },
    { label: "GO short window",              wind: 9,  gust: 16, wave: 0.35, coef: 40, sky: 'sunny',    rain: 0   },
    { label: "NO-GO — strong wind",          wind: 22, gust: 32, wave: 1.6,  coef: 40, sky: 'rain',     rain: 2.4 },
    { label: "NO-GO — big swell",            wind: 14, gust: 22, wave: 1.8,  coef: 43, sky: 'cloudy',   rain: 0.2 },
    { label: "GO best of the week",          wind: 6,  gust: 11, wave: 0.20, coef: 50, sky: 'sunny',    rain: 0   },
    { label: "NO-GO — big tides",            wind: 19, gust: 28, wave: 1.0,  coef: 108, sky: 'cloudy',  rain: 1.0 },
  ];
  for (let d = 0; d < 7; d++) {
    const arch = dayArchetypes[d];
    const sunrise = new Date(start); sunrise.setDate(start.getDate() + d); sunrise.setHours(6, 38 + d * 2, 0, 0);
    const sunset = new Date(start); sunset.setDate(start.getDate() + d); sunset.setHours(21, 14 + d, 0, 0);
    for (let h = 0; h < 24; h++) {
      const date = new Date(start); date.setDate(start.getDate() + d); date.setHours(h, 0, 0, 0);
      // wind diurnal: low at dawn, peak around 16h
      const t = (h - 4) / 24 * Math.PI;
      const diurnal = Math.max(0, Math.sin(t)) * 0.55 + 0.45;
      const wind = Math.max(0, arch.wind * diurnal + (Math.random() - 0.5) * 1.2);
      const gust = wind + (arch.gust - arch.wind) * (0.7 + 0.4 * Math.random());
      // Wind dir: SE prevails, but vary by day
      const baseDir = [130, 110, 150, 320, 100, 160, 290][d];
      const windDir = (baseDir + (Math.random() - 0.5) * 30 + 360) % 360;
      // Wave
      const wave = arch.wave * (0.85 + 0.3 * Math.random());
      const wavePeriod = 5.5 + Math.random() * 2.5;
      const waveDir = baseDir;
      // Tide: M2 semi-diurnal, period ≈ 12.42h, amp from coef
      const amp = arch.coef / 50; // half-amplitude in m
      const phase = (d * 24 + h) * 2 * Math.PI / 12.42 + d * 0.3;
      const tide = 2.7 + amp * Math.sin(phase); // height above chart datum
      // Depth under keel: chart depth (-0.6) + tide - draft (0.7); take min with channel (-1.0)
      const depthMooring = -0.6 + tide - 0.7;
      const depthChannel = -1.0 + tide - 0.7;
      const depth = Math.min(depthMooring, depthChannel);
      // Sky / cloud
      const cloud = arch.sky === 'sunny' ? 18 + Math.random() * 20
                  : arch.sky === 'cloudy' ? 65 + Math.random() * 25
                  : 90;
      const visibility = arch.sky === 'rain' ? 4000 + Math.random() * 2000 : 12000 + Math.random() * 5000;
      const precip = arch.rain * (Math.random() < 0.4 ? 0 : Math.random());
      const temp = 14 + Math.sin((h - 4) / 24 * Math.PI) * 5 + d * 0.3;
      const navigable = date >= new Date(sunrise.getTime() + 30 * 60000) && date <= new Date(sunset.getTime() - 60 * 60000);
      const score = scoreHourMock({ wind, gust, wave, depth, windDir, tideCoef: arch.coef, visibility, precip, navigable });
      series.push({
        time: date.toISOString(), date,
        dayKey: date.toDateString(),
        temp, precip, cloud, visibility,
        wind, gust, windDir,
        windSpeed: wind, windGust: gust, swell: wave,
        wave, waveDir, wavePeriod,
        seaMsl: tide - 2.7, tide,
        depth, depthMooring, depthChannel,
        navigable, sunrise, sunset,
        tideCoef: arch.coef,
        score,
        sky: arch.sky,
      });
    }
  }
  return series;
}

function scoreHourMock(h) {
  const t = THRESHOLDS;
  const ws = h.wind <= t.windGo ? 0 : h.wind <= t.windCaution ? 1 : 2;
  const gs = h.gust <= t.gustGo ? 0 : h.gust <= t.gustCaution ? 1 : 2;
  const ps = h.wave <= t.waveGo ? 0 : h.wave <= t.waveCaution ? 1 : 2;
  let ds = 0;
  if (h.depth == null) ds = 1;
  else if (h.depth < t.depthCaution) ds = 2;
  else if (h.depth < t.depthGo) ds = 1;
  let cs = 0;
  if (h.tideCoef >= t.coefNoGo && h.wind >= t.windCaution) cs = 2;
  else if (h.tideCoef >= t.coefNoGo) cs = 1;
  else if (h.tideCoef >= t.coefCaution && h.wind >= t.windCaution) cs = 1;
  let vs = 0;
  const vk = h.visibility / 1000;
  if (vk < t.visMinKm) vs = 2;
  else if (vk < t.visMinKm * 2) vs = 1;
  let rs = 0;
  if (h.precip > t.precipMax) rs = 2;
  else if (h.precip > 1) rs = 1;
  if (!h.navigable) return { verdict: 'night' };
  const worst = Math.max(ws, gs, ps, ds, cs, vs, rs);
  return { verdict: worst === 2 ? 'nogo' : worst === 1 ? 'caution' : 'go' };
}

// Find round-trip windows on the synthetic series
function findWindows(series, settings = { minDuration: 4 }) {
  const wins = [];
  let cur = null;
  for (let i = 0; i < series.length; i++) {
    const h = series[i];
    const ok = h.navigable && (h.score.verdict === 'go' || h.score.verdict === 'caution');
    const verdict = h.score.verdict;
    if (ok) {
      if (!cur) cur = { startIdx: i, endIdx: i, allGo: verdict === 'go' };
      else { cur.endIdx = i; if (verdict !== 'go') cur.allGo = false; }
    } else if (cur) {
      const hours = cur.endIdx - cur.startIdx + 1;
      if (hours >= settings.minDuration) wins.push({ start: series[cur.startIdx], end: series[cur.endIdx], hours, mode: cur.allGo ? 'go' : 'caution' });
      cur = null;
    }
  }
  if (cur) {
    const hours = cur.endIdx - cur.startIdx + 1;
    if (hours >= settings.minDuration) wins.push({ start: series[cur.startIdx], end: series[cur.endIdx], hours, mode: cur.allGo ? 'go' : 'caution' });
  }
  return wins;
}

function buildDays(series) {
  const map = new Map();
  for (const h of series) {
    if (!map.has(h.dayKey)) map.set(h.dayKey, []);
    map.get(h.dayKey).push(h);
  }
  const wins = findWindows(series);
  const days = [];
  let i = 0;
  for (const [k, hours] of map) {
    const date = new Date(hours[0].date);
    const label = i === 0 ? "Aujourd'hui" : i === 1 ? "Demain" : DOWS[date.getDay()];
    const dateStr = `${DOWS[date.getDay()]} ${date.getDate()} ${MONTHS[date.getMonth()]}`;
    const winsToday = wins.filter(w => w.start.dayKey === k);
    const bestWin = winsToday[0] || null;
    days.push({
      key: k, date, label, dateStr, dayIdx: i,
      hours,
      tideCoef: hours[0].tideCoef,
      window: bestWin,
      sunrise: hours[0].sunrise,
      sunset: hours[0].sunset,
      sky: hours[0].sky,
    });
    i++;
  }
  return days;
}

function dayVerdict(day) {
  if (!day.window) return 'nogo';
  return day.window.mode;
}

function windowStats(day, series) {
  const slice = day.window
    ? series.slice(series.indexOf(day.window.start), series.indexOf(day.window.end) + 1)
    : day.hours;
  return {
    windMax: Math.max(...slice.map(h => h.wind ?? 0)),
    windAvg: slice.reduce((a, h) => a + (h.wind ?? 0), 0) / slice.length,
    gustMax: Math.max(...slice.map(h => h.gust ?? 0)),
    swellMax: Math.max(...slice.map(h => h.wave ?? 0)),
    wavePeriod: slice.reduce((a, h) => a + (h.wavePeriod ?? 0), 0) / slice.length,
    rainMax: Math.max(...slice.map(h => h.precip ?? 0)),
    visMin: Math.min(...slice.map(h => (h.visibility != null ? h.visibility / 1000 : 99))),
    depthMin: Math.min(...slice.map(h => h.depth ?? 99)),
    tempAvg: slice.reduce((a, h) => a + (h.temp ?? 0), 0) / slice.length,
    cloudAvg: slice.reduce((a, h) => a + (h.cloud ?? 0), 0) / slice.length,
  };
}

function windSector(deg) {
  const d = ((deg % 360) + 360) % 360;
  return ['N','NE','E','SE','S','SO','O','NO'][Math.round(d / 45) % 8];
}

const VERDICT_LABEL = { go: 'GO', caution: 'PRUDENCE', nogo: 'NO-GO' };

// Build it once at module load
const MOCK_SERIES = buildMockSeries();
const MOCK_DAYS = buildDays(MOCK_SERIES);
const MOCK_WINDOWS = findWindows(MOCK_SERIES);

Object.assign(window, {
  TORPEN_LOC, BOAT, THRESHOLDS,
  DOWS, MONTHS, fmtTime, windSector, VERDICT_LABEL,
  buildMockSeries, findWindows, buildDays, dayVerdict, windowStats,
  MOCK_SERIES, MOCK_DAYS, MOCK_WINDOWS,
});
