<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Flight History</title>
<style>
@font-face{font-family:VT323;src:url('/static/fonts/VT323-Regular.ttf')}
:root{
  --navy:#00205b;--blue:#005587;--cyan:#0085ad;--steel:#6399ae;
  --mist:#b7c9d3;--silver:#d6d9dc;--white:#fff;--black:#000;
  --panel:rgba(0,85,135,.72);--line:rgba(183,201,211,.46);
}
*{box-sizing:border-box;letter-spacing:0}
body{margin:0;background:var(--navy);color:var(--white);font-family:VT323,monospace;font-size:20px}
button,input,select{font:inherit;letter-spacing:0}
.header{height:68px;display:flex;align-items:center;gap:16px;padding:0 24px;background:var(--cyan);border-bottom:1px solid var(--mist)}
.title{font-size:30px;flex:1}.sub{color:var(--silver);font-size:20px}
.back,.button{color:var(--white);background:var(--blue);border:1px solid var(--mist);padding:9px 14px;text-decoration:none;cursor:pointer;border-radius:2px}
.button:hover,.back:hover{background:var(--cyan)}.button.danger{background:#000;border-color:var(--silver)}
.content{padding:20px;max-width:1500px;margin:auto}
.tabs{display:flex;gap:8px;margin-bottom:16px}.tab.active{background:var(--cyan)}
.summary{display:grid;grid-template-columns:repeat(4,minmax(130px,1fr));gap:8px;margin-bottom:16px}
.stat{border:1px solid var(--line);background:var(--panel);padding:12px}.stat-label{color:var(--mist);font-size:16px}.stat-value{font-size:30px}
.layout{display:grid;grid-template-columns:minmax(430px,620px) minmax(480px,1fr);gap:16px;align-items:start}
.panel{border:1px solid var(--line);background:var(--panel);padding:14px}
.panel-head{display:flex;align-items:center;gap:8px;border-bottom:1px solid var(--line);padding-bottom:10px;margin-bottom:12px}
.panel-title{font-size:24px;flex:1}.icon{width:42px;height:40px;padding:0;font-size:25px}
.calendar-head,.calendar{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px}
.calendar-head div{color:var(--mist);text-align:center;padding:6px;font-size:16px}
.day{height:76px;background:rgba(0,32,91,.74);border:1px solid rgba(183,201,211,.24);color:var(--white);padding:8px;text-align:left;cursor:pointer;position:relative;border-radius:2px;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:8px;overflow:hidden}
.day:hover,.day.selected{border-color:var(--white);background:var(--cyan)}.day.empty{visibility:hidden}
.day-number{font-size:22px;line-height:1}.day-count{position:static;color:var(--mist);font-size:17px;line-height:.95;max-width:100%;overflow-wrap:anywhere}.day.selected .day-count{color:var(--white)}
.toolbar{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px}.toolbar input,.toolbar select{background:var(--black);color:var(--white);border:1px solid var(--steel);padding:8px;min-width:150px}
.range{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:12px}.range-actions{display:flex;gap:8px;grid-column:1/-1}
.status{color:var(--mist);min-height:28px;margin-top:8px}
.table-wrap{overflow:auto;max-height:620px;border:1px solid var(--line)}
table{width:100%;border-collapse:collapse;min-width:700px}th{position:sticky;top:0;background:var(--blue);text-align:left;color:var(--mist);padding:8px}
td{padding:7px 8px;border-top:1px solid rgba(183,201,211,.18)}tr:hover td{background:rgba(0,133,173,.2)}
.clickable-row{cursor:pointer}.callsign{color:var(--white);font-size:22px}.dim{color:var(--mist)}.hidden{display:none}
.json-overlay{position:fixed;inset:0;background:rgba(0,0,0,.72);z-index:100;display:flex;align-items:center;justify-content:center;padding:18px}
.json-dialog{width:min(900px,100%);max-height:88vh;background:var(--navy);border:1px solid var(--mist);display:flex;flex-direction:column}
.json-head{display:flex;align-items:center;gap:12px;padding:12px 14px;background:var(--blue);border-bottom:1px solid var(--line)}
.json-title{font-size:24px;flex:1}.json-close{width:40px;height:36px;padding:0;font-size:24px}
.json-body{margin:0;padding:15px;overflow:auto;color:var(--white);background:var(--black);font:14px/1.45 Consolas,"Courier New",monospace;white-space:pre-wrap;overflow-wrap:anywhere}
.json-overlay.hidden{display:none}
@media(max-width:950px){.layout{grid-template-columns:1fr}.summary{grid-template-columns:repeat(2,1fr)}.header{padding:0 12px}.sub{display:none}.content{padding:10px}}
</style>
</head>
<body>
<header class="header">
  <div class="title">Flight Database <span class="sub">/ History + Route Cache</span></div>
  <a class="back" href="/">BOARD</a>
</header>
<main class="content">
  <div class="tabs">
    <button class="button tab active" data-view="history">Flight History</button>
    <button class="button tab" data-view="routes">Route Cache</button>
  </div>

  <section id="history-view">
    <div id="summary" class="summary"></div>
    <div class="layout">
      <div>
        <div class="panel">
          <div class="panel-head">
            <button class="button icon" id="previous-month" title="Previous month">&#8249;</button>
            <div class="panel-title" id="month-title"></div>
            <button class="button icon" id="next-month" title="Next month">&#8250;</button>
          </div>
          <div class="calendar-head"><div>MON</div><div>TUE</div><div>WED</div><div>THU</div><div>FRI</div><div>SAT</div><div>SUN</div></div>
          <div id="calendar" class="calendar"></div>
        </div>
        <div class="panel" style="margin-top:16px">
          <div class="panel-head"><div class="panel-title">Manage History</div></div>
          <div class="range">
            <input id="range-start" type="date" aria-label="Start date">
            <input id="range-end" type="date" aria-label="End date">
            <div class="range-actions">
              <button class="button" id="export">Export CSV</button>
              <button class="button danger" id="delete-range">Delete Range</button>
            </div>
          </div>
          <div class="toolbar" style="margin-top:10px">
            <button class="button danger" id="delete-day">Delete Day</button>
            <button class="button danger" id="delete-week">Delete Week</button>
            <button class="button danger" id="delete-month">Delete Month</button>
          </div>
          <div id="status" class="status"></div>
        </div>
      </div>
      <div class="panel">
        <div class="panel-head"><div class="panel-title" id="day-title">Select a day</div></div>
        <div class="toolbar">
          <input id="history-search" placeholder="Search callsign or route">
        </div>
        <div class="table-wrap"><table>
          <thead><tr><th>Time</th><th>Callsign</th><th>Route</th><th>Airline</th><th>Aircraft</th><th>Altitude</th></tr></thead>
          <tbody id="history-body"><tr><td colspan="6" class="dim">Choose a calendar day to view flights.</td></tr></tbody>
        </table></div>
      </div>
    </div>
  </section>

  <section id="routes-view" class="hidden">
    <div class="panel">
      <div class="panel-head"><div class="panel-title">Route Cache</div></div>
      <div class="toolbar">
        <input id="route-search" placeholder="Search callsign, airline, route, aircraft">
        <select id="route-source"><option value="">All sources</option></select>
      </div>
      <div class="table-wrap"><table>
        <thead><tr><th>Callsign</th><th>Seen</th><th>Route</th><th>Airline</th><th>Aircraft</th><th>Source</th><th>Cache Hits</th><th>Last Seen</th></tr></thead>
        <tbody id="route-body"></tbody>
      </table></div>
    </div>
  </section>
</main>
<div id="json-overlay" class="json-overlay hidden" role="dialog" aria-modal="true" aria-labelledby="json-title">
  <div class="json-dialog">
    <div class="json-head">
      <div id="json-title" class="json-title">Raw JSON</div>
      <button id="json-close" class="button json-close" type="button" title="Close">&times;</button>
    </div>
    <pre id="json-body" class="json-body">Loading...</pre>
  </div>
</div>
<script>
const state={month:new Date(),selected:null,days:new Map(),flights:[],routes:[]};
state.month=new Date(state.month.getFullYear(),state.month.getMonth(),1);
const pad=n=>String(n).padStart(2,'0');
const dateText=d=>`${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`;
const monthText=d=>`${d.getFullYear()}-${pad(d.getMonth()+1)}`;
const esc=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));

async function loadMonth(){
  const data=await fetch(`/history/calendar/json?month=${monthText(state.month)}`).then(r=>r.json());
  state.days=new Map((data.days||[]).map(d=>[d.date,d]));
  document.getElementById('month-title').textContent=state.month.toLocaleDateString(undefined,{month:'long',year:'numeric'});
  const t=data.totals||{};
  document.getElementById('summary').innerHTML=`
    <div class="stat"><div class="stat-label">Flight Events</div><div class="stat-value">${t.events||0}</div></div>
    <div class="stat"><div class="stat-label">Days Recorded</div><div class="stat-value">${t.days||0}</div></div>
    <div class="stat"><div class="stat-label">First Date</div><div class="stat-value">${t.first_date||'-'}</div></div>
    <div class="stat"><div class="stat-label">Latest Date</div><div class="stat-value">${t.last_date||'-'}</div></div>`;
  renderCalendar();
}

function renderCalendar(){
  const year=state.month.getFullYear(),month=state.month.getMonth();
  const first=(new Date(year,month,1).getDay()+6)%7;
  const count=new Date(year,month+1,0).getDate();
  const cells=Array.from({length:first},()=>'<button class="day empty"></button>');
  for(let number=1;number<=count;number++){
    const date=`${year}-${pad(month+1)}-${pad(number)}`,day=state.days.get(date),selected=date===state.selected?' selected':'';
    cells.push(`<button class="day${selected}" data-date="${date}"><span class="day-number">${number}</span>${day?`<span class="day-count">${day.count} flights</span>`:''}</button>`);
  }
  document.getElementById('calendar').innerHTML=cells.join('');
  document.querySelectorAll('.day[data-date]').forEach(button=>button.onclick=()=>selectDay(button.dataset.date));
}

async function selectDay(date){
  state.selected=date;
  document.getElementById('range-start').value=date;
  document.getElementById('range-end').value=date;
  renderCalendar();
  const log=await fetch(`/counter?start=${date}&end=${date}`).then(r=>r.json());
  state.flights=((log[date]||{}).flights||[]).sort((a,b)=>
    String(b.seen_at||`${date} ${b.time||''}`).localeCompare(String(a.seen_at||`${date} ${a.time||''}`))
  );
  document.getElementById('day-title').textContent=`Flights for ${date} (${state.flights.length})`;
  renderFlights();
}

function renderFlights(){
  const q=document.getElementById('history-search').value.trim().toUpperCase();
  const rows=state.flights.filter(f=>`${f.callsign} ${f.origin} ${f.dest} ${f.airline} ${f.aircraft_type}`.toUpperCase().includes(q));
  document.getElementById('history-body').innerHTML=rows.map(f=>`<tr class="clickable-row" data-event-id="${f.id}" title="View raw JSON">
    <td class="dim">${esc(f.time)}</td><td class="callsign">${esc(f.callsign)}</td>
    <td>${esc(f.origin||'?')} - ${esc(f.dest||'?')}</td><td>${esc(f.airline||'')}</td>
    <td>${esc(f.aircraft_type||'')}</td><td>${f.altitude==null?'':esc(Math.round(f.altitude))}</td>
  </tr>`).join('')||'<tr><td colspan="6" class="dim">No flights found.</td></tr>';
  document.querySelectorAll('#history-body tr[data-event-id]').forEach(row=>row.onclick=()=>showRaw(`/database/history/${row.dataset.eventId}/json`,`${row.querySelector('.callsign').textContent} history`));
}

function weekRange(date){
  const d=new Date(date+'T12:00:00'),offset=(d.getDay()+6)%7,start=new Date(d);
  start.setDate(d.getDate()-offset);const end=new Date(start);end.setDate(start.getDate()+6);
  return [dateText(start),dateText(end)];
}
function monthRange(){const y=state.month.getFullYear(),m=state.month.getMonth();return[dateText(new Date(y,m,1)),dateText(new Date(y,m+1,0))]}
async function deleteRange(start,end,label){
  if(!start||!end){document.getElementById('status').textContent='Select a date range first.';return}
  const confirmation=prompt(`Delete ${label} (${start} to ${end})? Type DELETE to confirm.`);
  if(confirmation!=='DELETE')return;
  const response=await fetch('/history/range',{method:'DELETE',headers:{'Content-Type':'application/json'},body:JSON.stringify({start,end,confirm:confirmation})});
  const data=await response.json();
  document.getElementById('status').textContent=data.ok?`Deleted ${data.deleted} flight records.`:(data.message||'Delete failed.');
  state.selected=null;state.flights=[];renderFlights();await loadMonth();
}

async function loadRoutes(){
  const data=await fetch('/database/json').then(r=>r.json());state.routes=data.rows||[];
  const sources=[...new Set(state.routes.map(r=>r.source).filter(Boolean))].sort();
  document.getElementById('route-source').innerHTML='<option value="">All sources</option>'+sources.map(s=>`<option>${esc(s)}</option>`).join('');
  renderRoutes();
}
function renderRoutes(){
  const q=document.getElementById('route-search').value.trim().toUpperCase(),source=document.getElementById('route-source').value;
  const rows=state.routes.filter(r=>(!source||r.source===source)&&`${r.callsign} ${r.airline} ${r.plane} ${r.origin} ${r.destination}`.toUpperCase().includes(q));
  document.getElementById('route-body').innerHTML=rows.map(r=>`<tr class="${r.in_route_cache?'clickable-row':''}" data-callsign="${r.in_route_cache?esc(r.callsign):''}" title="${r.in_route_cache?'View raw JSON':''}"><td class="callsign">${esc(r.callsign)}</td><td>${r.seen_count}</td><td>${esc(r.origin)} - ${esc(r.destination)}</td><td>${esc(r.airline)}</td><td>${esc(r.plane)}</td><td>${esc(r.source)}</td><td>${r.cache_hits}</td><td>${esc(r.last_seen)}</td></tr>`).join('');
  document.querySelectorAll('#route-body tr[data-callsign]:not([data-callsign=""])').forEach(row=>row.onclick=()=>showRaw(`/database/route/${encodeURIComponent(row.dataset.callsign)}/json`,`${row.dataset.callsign} route cache`));
}

async function showRaw(url,title){
  const overlay=document.getElementById('json-overlay'),body=document.getElementById('json-body');
  document.getElementById('json-title').textContent=title;
  body.textContent='Loading...';overlay.classList.remove('hidden');
  try{
    const response=await fetch(url,{cache:'no-store'}),data=await response.json();
    body.textContent=JSON.stringify(data,null,2);
  }catch(error){
    body.textContent=`Could not load JSON: ${error.message}`;
  }
}
function closeRaw(){document.getElementById('json-overlay').classList.add('hidden')}

document.getElementById('previous-month').onclick=()=>{state.month.setMonth(state.month.getMonth()-1);loadMonth()};
document.getElementById('next-month').onclick=()=>{state.month.setMonth(state.month.getMonth()+1);loadMonth()};
document.getElementById('history-search').oninput=renderFlights;
document.getElementById('route-search').oninput=renderRoutes;document.getElementById('route-source').onchange=renderRoutes;
document.getElementById('json-close').onclick=closeRaw;
document.getElementById('json-overlay').onclick=event=>{if(event.target.id==='json-overlay')closeRaw()};
document.addEventListener('keydown',event=>{if(event.key==='Escape')closeRaw()});
document.getElementById('delete-day').onclick=()=>state.selected&&deleteRange(state.selected,state.selected,'this day');
document.getElementById('delete-week').onclick=()=>{if(state.selected){const r=weekRange(state.selected);deleteRange(r[0],r[1],'this week')}};
document.getElementById('delete-month').onclick=()=>{const r=monthRange();deleteRange(r[0],r[1],'this month')};
document.getElementById('delete-range').onclick=()=>deleteRange(document.getElementById('range-start').value,document.getElementById('range-end').value,'this range');
document.getElementById('export').onclick=()=>{const s=document.getElementById('range-start').value,e=document.getElementById('range-end').value;location.href=`/history/export.csv?start=${s}&end=${e}`};
document.querySelectorAll('.tab').forEach(tab=>tab.onclick=()=>{document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));tab.classList.add('active');document.getElementById('history-view').classList.toggle('hidden',tab.dataset.view!=='history');document.getElementById('routes-view').classList.toggle('hidden',tab.dataset.view!=='routes');if(tab.dataset.view==='routes'&&!state.routes.length)loadRoutes()});
loadMonth().then(()=>{const latest=[...state.days.keys()].sort().pop();if(latest)selectDay(latest)});
</script>
</body>
</html>
