#!/usr/bin/env python3
"""TMED-II Installation Tracker — minimal HTTP server with Jinja2 + MinIO photos."""

import sqlite3
import os
import base64
import io
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
from jinja2 import Template
from minio import Minio

DB = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tmed2_install.db")
LOGO = "/home/borbolla/clawd/assets/branding/logo.png"
PORT = 8877

# MinIO config
MINIO_HOST = "192.168.100.251:9000"
MINIO_KEY = "minioadmin"
MINIO_SECRET = "minioadmin123"
MINIO_BUCKET = "tmed2-photos"

mc = Minio(MINIO_HOST, access_key=MINIO_KEY, secret_key=MINIO_SECRET, secure=False)

# Encode logo
with open(LOGO, "rb") as f:
    LOGO_B64 = base64.b64encode(f.read()).decode()


TEMPLATE = Template("""\
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>TMED-II Tracker</title>
<style>
  :root {
    --bg: #0d1117; --bg-card: #161b22; --border: #30363d;
    --text: #c9d1d9; --text-dim: #484f58; --text-muted: #8b949e;
    --text-bright: #f0f6fc;
    --blue: #1f6feb; --blue-light: #58a6ff;
    --green: #238636; --green-light: #3fb950;
    --orange: #9e6a03; --orange-light: #d29922;
    --purple: #8957e5; --purple-light: #a371f7;
    --red: #da3633; --red-light: #f85149;
  }
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body { font-family: -apple-system, system-ui, sans-serif; background: var(--bg); color: var(--text); }

  /* Header */
  .header { display: flex; align-items: center; justify-content: space-between; padding: 16px 24px; border-bottom: 1px solid var(--border); }
  .header img { height: 28px; opacity: 0.9; }
  .header h1 { font-size: 1rem; font-weight: 500; color: var(--text-muted); letter-spacing: 0.03em; }
  .header .project { font-size: 0.7rem; color: var(--text-dim); }

  .main { padding: 20px 24px; max-width: 1400px; margin: 0 auto; }

  h2 { font-size: 0.75rem; font-weight: 500; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.08em; margin: 24px 0 10px; }

  /* Cards */
  .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; }
  .card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; padding: 14px; }
  .card .val { font-size: 1.6rem; font-weight: 700; color: var(--text-bright); font-variant-numeric: tabular-nums; }
  .card .lbl { font-size: 0.7rem; color: var(--text-muted); margin-top: 2px; }

  /* Progress */
  .line-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; padding: 14px; margin-bottom: 8px; }
  .line-card .name { font-size: 0.85rem; font-weight: 600; color: var(--text-bright); margin-bottom: 8px; }
  .line-card .meta { font-size: 0.7rem; color: var(--text-muted); }
  .bar-row { display: flex; align-items: center; gap: 6px; margin-top: 5px; font-size: 0.7rem; }
  .bar-label { width: 80px; text-align: right; color: var(--text-muted); }
  .bar-bg { flex: 1; height: 10px; background: #21262d; border-radius: 3px; overflow: hidden; }
  .bar-fill { height: 100%; border-radius: 3px; }
  .bar-fill.rcv { background: var(--blue); } .bar-fill.inst { background: var(--green); }
  .bar-fill.elec { background: var(--orange); } .bar-fill.air { background: var(--purple); }
  .bar-fill.comm { background: var(--red); }
  .bar-count { width: 36px; font-size: 0.65rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }

  /* Tabs */
  .tabs { display: flex; border-bottom: 1px solid var(--border); margin-top: 20px; }
  .tab { padding: 7px 14px; font-size: 0.75rem; color: var(--text-muted); cursor: pointer; border-bottom: 2px solid transparent; user-select: none; }
  .tab.active { color: var(--text-bright); border-bottom-color: var(--blue); }
  .tab:hover { color: var(--text-bright); }
  .tab-content { display: none; } .tab-content.active { display: block; }

  /* Filter */
  .filter { margin: 10px 0; display: flex; gap: 6px; }
  .fbtn { padding: 3px 10px; border-radius: 10px; font-size: 0.7rem; border: 1px solid var(--border); background: var(--bg-card); color: var(--text-muted); cursor: pointer; }
  .fbtn.active { border-color: var(--blue); color: var(--blue-light); }

  /* Table */
  table { width: 100%; border-collapse: collapse; font-size: 0.75rem; }
  thead th { background: var(--bg-card); color: var(--text-dim); font-weight: 500; text-align: left; padding: 6px 8px; position: sticky; top: 0; z-index: 1; border-bottom: 1px solid var(--border); }
  tbody td { padding: 5px 8px; border-bottom: 1px solid #21262d; vertical-align: middle; }
  tbody tr:hover { background: var(--bg-card); }
  tbody tr.expandable { cursor: pointer; }
  .mono { font-family: 'SF Mono', Consolas, monospace; font-size: 0.7rem; }
  .dim { color: var(--text-dim); }
  .wt { text-align: right; }

  /* Badges */
  .badge { display: inline-block; padding: 1px 6px; border-radius: 8px; font-size: 0.65rem; font-weight: 500; }
  .badge.yes { background: var(--green); color: #fff; }
  .badge.no { background: #21262d; color: var(--text-dim); }
  .badge.motor { background: #1f3a5f; color: var(--blue-light); }
  .badge.case { background: #3b2e1a; color: var(--orange-light); }
  .badge.assy { background: #2a1f3d; color: var(--purple-light); }
  .photo-count { color: var(--blue-light); cursor: pointer; }
  .photo-count.zero { color: var(--text-dim); cursor: default; }

  /* Photo modal */
  .modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.85); z-index: 100; justify-content: center; align-items: center; }
  .modal-overlay.show { display: flex; }
  .modal { background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; max-width: 900px; width: 95%; max-height: 90vh; overflow-y: auto; padding: 20px; }
  .modal h3 { font-size: 0.9rem; color: var(--text-bright); margin-bottom: 4px; }
  .modal .sub { font-size: 0.7rem; color: var(--text-muted); margin-bottom: 12px; }
  .modal .close { position: absolute; top: 12px; right: 16px; color: var(--text-muted); cursor: pointer; font-size: 1.2rem; }
  .photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px; }
  .photo-grid img { width: 100%; border-radius: 4px; border: 1px solid var(--border); cursor: pointer; transition: transform 0.2s; }
  .photo-grid img:hover { transform: scale(1.02); border-color: var(--blue); }
  .photo-grid .label { font-size: 0.65rem; color: var(--text-dim); margin-top: 2px; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* Lightbox */
  .lightbox { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.95); z-index: 200; justify-content: center; align-items: center; cursor: zoom-out; }
  .lightbox.show { display: flex; }
  .lightbox img { max-width: 95vw; max-height: 95vh; object-fit: contain; }

  /* Footer */
  .footer { text-align: center; padding: 20px; font-size: 0.65rem; color: var(--text-dim); border-top: 1px solid var(--border); margin-top: 30px; }
</style>
</head>
<body>

<div class="header">
  <div>
    <img src="data:image/png;base64,{{ logo_b64 }}" alt="Borbolla">
  </div>
  <div style="text-align:right">
    <h1>TMED-II Phase III</h1>
    <div class="project">Installation Tracker &middot; {{ summary.machines }} machines &middot; {{ summary.containers }} containers</div>
  </div>
</div>

<div class="main">

<div class="cards">
  <div class="card"><div class="val">{{ summary.machines }}</div><div class="lbl">Machines</div></div>
  <div class="card"><div class="val">{{ summary.containers }}</div><div class="lbl">Containers</div></div>
  <div class="card"><div class="val">{{ "%.0f"|format(summary.gross_t) }}T</div><div class="lbl">Gross Weight</div></div>
  <div class="card"><div class="val">{{ summary.linked_photos }}</div><div class="lbl">Photos Linked</div></div>
  <div class="card"><div class="val">{{ summary.received }}/{{ summary.machines }}</div><div class="lbl">Received</div></div>
  <div class="card"><div class="val">{{ summary.commissioned }}/{{ summary.machines }}</div><div class="lbl">Commissioned</div></div>
</div>

<h2>Progress</h2>
{% for lp in line_progress %}
<div class="line-card">
  <div class="name"><span class="badge {{ lp.css }}">{{ lp.line }}</span> <span class="meta">{{ lp.total }} machines &middot; {{ "%.0f"|format(lp.gross_t) }}T &middot; {{ lp.arrival }}</span></div>
  {% for step in lp.steps %}
  <div class="bar-row">
    <div class="bar-label">{{ step.label }}</div>
    <div class="bar-bg"><div class="bar-fill {{ step.css }}" style="width:{{ step.pct }}%"></div></div>
    <div class="bar-count">{{ step.done }}/{{ lp.total }}</div>
  </div>
  {% endfor %}
</div>
{% endfor %}

<div class="tabs">
  <div class="tab active" onclick="showTab('machines')">Machines</div>
  <div class="tab" onclick="showTab('containers')">Containers</div>
</div>

<div id="machines" class="tab-content active">
<div class="filter">
  <span class="fbtn active" onclick="filterLine(this,'all')">All</span>
  <span class="fbtn" onclick="filterLine(this,'Motor')">Motor</span>
  <span class="fbtn" onclick="filterLine(this,'Case')">Case</span>
  <span class="fbtn" onclick="filterLine(this,'Assembly')">Assembly</span>
</div>
<table>
<thead><tr>
  <th>#</th><th>Line</th><th>Korean</th><th>English</th>
  <th class="wt">T</th><th>Container</th><th>Arrival</th>
  <th>Rcv</th><th>Inst</th><th>Elec</th><th>Air</th><th>Comm</th><th>Photos</th>
</tr></thead>
<tbody>
{% for m in machines %}
<tr class="{{ 'expandable' if m.photo_count else '' }}" data-line="{{ m.line }}" {% if m.photo_count %}onclick="showPhotos({{ m.id }}, '{{ m.english_name|e }}', '{{ m.korean_name|e }}')"{% endif %}>
  <td class="mono dim">{{ m.id }}</td>
  <td><span class="badge {{ m.line_css }}">{{ m.line_short }}</span></td>
  <td>{{ m.korean_name }}</td>
  <td>{{ m.english_name[:45] }}{{ '...' if m.english_name|length > 45 else '' }}</td>
  <td class="wt mono">{{ "%.1f"|format(m.weight_gross_t or 0) }}</td>
  <td class="mono">{{ m.container_label or '—' }}</td>
  <td class="mono">{{ m.arrival_group or '' }}</td>
  <td>{{ '<span class="badge yes">Y</span>'|safe if m.received else '<span class="badge no">·</span>'|safe }}</td>
  <td>{{ '<span class="badge yes">Y</span>'|safe if m.installed else '<span class="badge no">·</span>'|safe }}</td>
  <td>{{ '<span class="badge yes">Y</span>'|safe if m.electrical else '<span class="badge no">·</span>'|safe }}</td>
  <td>{{ '<span class="badge yes">Y</span>'|safe if m.air else '<span class="badge no">·</span>'|safe }}</td>
  <td>{{ '<span class="badge yes">Y</span>'|safe if m.commissioned else '<span class="badge no">·</span>'|safe }}</td>
  <td class="photo-count {{ 'zero' if not m.photo_count else '' }}">{{ m.photo_count or '—' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>

<div id="containers" class="tab-content">
<table>
<thead><tr>
  <th>#</th><th>Container</th><th>Type</th><th>Line</th>
  <th>Vessel</th><th>Sailing</th><th>Arrival</th>
  <th>Day</th><th>Forklift</th><th>Items</th><th>Unloaded</th>
</tr></thead>
<tbody>
{% for c in containers %}
<tr>
  <td class="mono dim">{{ c.id }}</td>
  <td class="mono">{{ c.supplier_prefix }}-{{ c.container_num }}</td>
  <td class="mono">{{ c.container_type or '' }}</td>
  <td>{{ c.line or '' }}</td>
  <td>{{ (c.vessel or '')[:20] }}</td>
  <td class="mono">{{ c.sailing_date or '' }}</td>
  <td class="mono">{{ c.est_arrival or '' }}</td>
  <td class="mono">{{ c.unload_day or '' }}</td>
  <td>{{ c.forklift_class or '' }}</td>
  <td class="mono">{{ c.machine_count }}</td>
  <td>{{ '<span class="badge yes">Y</span>'|safe if c.unloaded else '<span class="badge no">·</span>'|safe }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>

</div>

<!-- Photo Modal -->
<div class="modal-overlay" id="photoModal" onclick="if(event.target===this)closeModal()">
  <div class="modal" style="position:relative">
    <span class="close" onclick="closeModal()">&times;</span>
    <h3 id="modalTitle"></h3>
    <div class="sub" id="modalSub"></div>
    <div class="photo-grid" id="photoGrid"></div>
  </div>
</div>

<!-- Lightbox -->
<div class="lightbox" id="lightbox" onclick="this.classList.remove('show')">
  <img id="lightboxImg" src="">
</div>

<div class="footer">TMED-II Phase III &middot; Borbolla Automation Inc &middot; Hyundai Transys Pesquería</div>

<script>
function showTab(id) {
  document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
  document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
  document.getElementById(id).classList.add('active');
  event.target.classList.add('active');
}
function filterLine(btn, line) {
  document.querySelectorAll('.fbtn').forEach(b => b.classList.remove('active'));
  btn.classList.add('active');
  document.querySelectorAll('#machines tbody tr').forEach(tr => {
    tr.style.display = (line === 'all' || tr.dataset.line.includes(line)) ? '' : 'none';
  });
}
function showPhotos(machineId, en, kr) {
  document.getElementById('modalTitle').textContent = en;
  document.getElementById('modalSub').textContent = kr;
  const grid = document.getElementById('photoGrid');
  grid.innerHTML = '<div style="color:#8b949e;font-size:0.8rem">Loading...</div>';
  document.getElementById('photoModal').classList.add('show');
  fetch('/photos?machine_id=' + machineId)
    .then(r => r.json())
    .then(photos => {
      grid.innerHTML = '';
      photos.forEach(p => {
        const div = document.createElement('div');
        const img = document.createElement('img');
        img.src = '/photo/' + encodeURIComponent(p.key);
        img.loading = 'lazy';
        img.onclick = function(e) { e.stopPropagation(); openLightbox(this.src); };
        const lbl = document.createElement('div');
        lbl.className = 'label';
        lbl.textContent = p.key.split('/').pop();
        div.appendChild(img);
        div.appendChild(lbl);
        grid.appendChild(div);
      });
      if (!photos.length) grid.innerHTML = '<div style="color:#8b949e">No photos linked</div>';
    });
}
function closeModal() { document.getElementById('photoModal').classList.remove('show'); }
function openLightbox(src) {
  document.getElementById('lightboxImg').src = src;
  document.getElementById('lightbox').classList.add('show');
}
document.addEventListener('keydown', e => {
  if (e.key === 'Escape') {
    document.getElementById('lightbox').classList.remove('show');
    closeModal();
  }
});
</script>
</body>
</html>
""")


def query_db():
    db = sqlite3.connect(DB)
    db.row_factory = sqlite3.Row
    c = db.cursor()

    summary = {}
    c.execute("SELECT count(*) FROM machines")
    summary["machines"] = c.fetchone()[0]
    c.execute("SELECT count(*) FROM containers")
    summary["containers"] = c.fetchone()[0]
    c.execute("SELECT coalesce(sum(weight_gross_t),0) FROM machines")
    summary["gross_t"] = c.fetchone()[0]
    c.execute("SELECT count(*) FROM machine_photos WHERE machine_id IS NOT NULL")
    summary["linked_photos"] = c.fetchone()[0]
    c.execute("SELECT coalesce(sum(received),0) FROM machines")
    summary["received"] = c.fetchone()[0]
    c.execute("SELECT coalesce(sum(commissioned),0) FROM machines")
    summary["commissioned"] = c.fetchone()[0]

    line_progress = []
    c.execute("""
        SELECT line, count(*) total,
            coalesce(sum(weight_gross_t),0) gross_t,
            sum(received) rcv, sum(installed) inst,
            sum(electrical) elec, sum(air) air, sum(commissioned) comm,
            min(arrival_group) arrival
        FROM machines GROUP BY line ORDER BY min(arrival_group)
    """)
    for row in c.fetchall():
        css = "motor" if "Motor" in row["line"] else ("case" if "Case" in row["line"] else "assy")
        total = row["total"]
        steps = [
            {"label": "Received", "done": row["rcv"] or 0, "pct": (row["rcv"] or 0) / total * 100, "css": "rcv"},
            {"label": "Installed", "done": row["inst"] or 0, "pct": (row["inst"] or 0) / total * 100, "css": "inst"},
            {"label": "Electrical", "done": row["elec"] or 0, "pct": (row["elec"] or 0) / total * 100, "css": "elec"},
            {"label": "Air", "done": row["air"] or 0, "pct": (row["air"] or 0) / total * 100, "css": "air"},
            {"label": "Commissioned", "done": row["comm"] or 0, "pct": (row["comm"] or 0) / total * 100, "css": "comm"},
        ]
        line_progress.append({
            "line": row["line"], "total": total, "gross_t": row["gross_t"],
            "arrival": row["arrival"], "css": css, "steps": steps,
        })

    c.execute("""
        SELECT m.*,
            c.supplier_prefix || '-' || c.container_num AS container_label,
            (SELECT count(*) FROM machine_photos p WHERE p.machine_id = m.id) AS photo_count
        FROM machines m LEFT JOIN containers c ON m.container_id = c.id
        ORDER BY m.arrival_group, m.line, m.id
    """)
    machines_list = []
    for row in c.fetchall():
        line = row["line"] or ""
        css = "motor" if "Motor" in line else ("case" if "Case" in line else "assy")
        short = "Motor" if "Motor" in line else ("Case" if "Case" in line else "Assy")
        machines_list.append({**dict(row), "line_css": css, "line_short": short})

    c.execute("""
        SELECT ct.*,
            (SELECT count(*) FROM machines m WHERE m.container_id = ct.id) AS machine_count
        FROM containers ct
        ORDER BY ct.est_arrival, ct.unload_day, ct.supplier_prefix, ct.container_num
    """)
    containers_list = [dict(row) for row in c.fetchall()]

    db.close()
    return summary, line_progress, machines_list, containers_list


def get_photos_for_machine(machine_id):
    db = sqlite3.connect(DB)
    c = db.cursor()
    c.execute("SELECT minio_key FROM machine_photos WHERE machine_id = ?", (machine_id,))
    photos = [{"key": row[0]} for row in c.fetchall()]
    db.close()
    return photos


# Photo cache to avoid re-fetching from MinIO
_photo_cache = {}


def get_photo_bytes(minio_key):
    if minio_key in _photo_cache:
        return _photo_cache[minio_key]
    try:
        resp = mc.get_object(MINIO_BUCKET, minio_key)
        data = resp.read()
        resp.close()
        _photo_cache[minio_key] = data
        return data
    except Exception:
        return None


class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        parsed = urlparse(self.path)
        path = parsed.path
        params = parse_qs(parsed.query)

        if path == "/photos":
            mid = int(params.get("machine_id", [0])[0])
            photos = get_photos_for_machine(mid)
            import json
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(json.dumps(photos).encode())

        elif path.startswith("/photo/"):
            from urllib.parse import unquote
            minio_key = unquote(path[7:])
            data = get_photo_bytes(minio_key)
            if data:
                ext = minio_key.rsplit(".", 1)[-1].lower()
                ct = {"png": "image/png", "jpg": "image/jpeg", "jpeg": "image/jpeg"}.get(ext, "image/jpeg")
                self.send_response(200)
                self.send_header("Content-Type", ct)
                self.send_header("Cache-Control", "max-age=86400")
                self.end_headers()
                self.wfile.write(data)
            else:
                self.send_response(404)
                self.end_headers()

        elif path == "/manifest":
            manifest_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "container_manifest.html")
            with open(manifest_path, "rb") as f:
                data = f.read()
            self.send_response(200)
            self.send_header("Content-Type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write(data)

        else:
            summary, line_progress, machines, containers = query_db()
            html = TEMPLATE.render(
                summary=summary, line_progress=line_progress,
                machines=machines, containers=containers,
                logo_b64=LOGO_B64,
            )
            self.send_response(200)
            self.send_header("Content-Type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write(html.encode())

    def log_message(self, fmt, *args):
        pass  # quiet


if __name__ == "__main__":
    print(f"TMED-II Tracker → http://0.0.0.0:{PORT}")
    HTTPServer(("0.0.0.0", PORT), Handler).serve_forever()
