package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

func runtimeDir() string {
	exe, err := os.Executable()
	if err != nil {
		return "runtime"
	}
	return filepath.Join(filepath.Dir(exe), "runtime")
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", handleIndex)
	mux.HandleFunc("/api/state", handleState)

	addr := "127.0.0.1:18181"
	go openBrowser("http://" + addr)
	log.Printf("gui listening on http://%s", addr)
	log.Fatal(http.ListenAndServe(addr, mux))
}

func handleIndex(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	html := `<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="refresh" content="3">
  <title>VRTW_Tool</title>
  <style>
    body{font-family:sans-serif;background:#111;color:#eee;margin:20px}
    .grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
    .card{background:#1b1b1b;border:1px solid #333;border-radius:12px;padding:16px}
    table{width:100%;border-collapse:collapse}
    td,th{border-bottom:1px solid #333;padding:6px;text-align:left}
    th{cursor:pointer;user-select:none}
    th:hover{color:#8ff}
    .on{color:#5ff28f}.off{color:#ff8a8a}
  </style>
</head>
<body>
  <h1>VRTW_Tool</h1>
  <div id="root">loading...</div>
  <script>
    const sortKey = 'vrc_osc_gui_sort';
    const defaultSort = { key: 'name', dir: 1 };
    let sortState = (() => {
      try {
        const raw = localStorage.getItem(sortKey);
        return raw ? JSON.parse(raw) : defaultSort;
      } catch (_) {
        return defaultSort;
      }
    })();

    function setSort(key) {
      if (sortState.key === key) {
        sortState.dir = sortState.dir * -1;
      } else {
        sortState = { key: key, dir: 1 };
      }
      localStorage.setItem(sortKey, JSON.stringify(sortState));
      load();
    }

    function compareGuests(a, b) {
      if (sortState.key === 'name') {
        const v = a.name.localeCompare(b.name, 'ja');
        return v * sortState.dir;
      }
      if (sortState.key === 'presence') {
        const av = Number(a.present);
        const bv = Number(b.present);
        if (av !== bv) {
          return (bv - av) * sortState.dir;
        }
        return a.name.localeCompare(b.name, 'ja');
      }
      if (sortState.key === 'status') {
        const av = Number(!a.present);
        const bv = Number(!b.present);
        if (av !== bv) {
          return (av - bv) * sortState.dir;
        }
        return a.name.localeCompare(b.name, 'ja');
      }
      return a.name.localeCompare(b.name, 'ja');
    }

    async function load(){
      const r = await fetch('/api/state');
      const j = await r.json();
      const guests = [...j.guests].sort(compareGuests);
      const presentCount = guests.filter(g => g.present).length;
      const rows = guests.map(g => {
        const status = g.present ? '在席' : (g.absent_for || '1分未満');
        return '<tr><td>' + esc(g.name) + '</td><td>' + esc(status) + '</td></tr>';
      }).join('');
      document.getElementById('root').innerHTML =
        '<div class="grid">' +
          '<div class="card">' +
            '<h2>状態</h2>' +
            '<p>World: ' + esc(j.world || '') + '</p>' +
            '<p>Discord: <span class="' + (j.discord_muted ? 'on' : 'off') + '">' + (j.discord_muted ? 'Muted' : 'Unmuted') + '</span></p>' +
            '<p>OCR: ' + esc(j.ocr || '') + '</p>' +
            '<p>翻訳: ' + esc(j.translate || '未実装') + '</p>' +
          '</div>' +
          '<div class="card">' +
            '<h2>ゲスト (' + presentCount + '/' + j.guest_count + ')</h2>' +
            '<table>' +
              '<tr>' +
                '<th data-sort="name">名前' + sortMark('name') + '</th>' +
                '<th data-sort="presence">在席' + sortMark('presence') + '</th>' +
              '</tr>' +
              rows +
            '</table>' +
          '</div>' +
        '</div>';
      document.querySelectorAll('th[data-sort]').forEach(function(el) {
        el.style.cursor = 'pointer';
        el.onclick = function() {
          setSort(el.getAttribute('data-sort'));
        };
      });
    }

    function sortMark(key) {
      if (sortState.key !== key) return '';
      return sortState.dir > 0 ? ' ▲' : ' ▼';
    }

    function esc(s){ return (s || '').replace(/[&<>"]/g, function(m){ return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[m]; }); }
    setInterval(load, 3000);
    load();
  </script>
</body>
</html>`
	_, _ = fmt.Fprint(w, html)
}

func handleState(w http.ResponseWriter, r *http.Request) {
	statePath := filepath.Join(runtimeDir(), "state.json")
	body, err := os.ReadFile(statePath)
	if err != nil {
		_ = json.NewEncoder(w).Encode(map[string]any{
			"world":         "",
			"discord_muted": false,
			"ocr":           "",
			"translate":     "",
			"guests":        []any{},
			"guest_count":   0,
			"error":         err.Error(),
		})
		return
	}
	var state map[string]any
	if err := json.Unmarshal(body, &state); err != nil {
		_ = json.NewEncoder(w).Encode(map[string]any{"error": err.Error()})
		return
	}
	guests := loadGuestSnapshot()
	state["guests"] = guests
	state["guest_count"] = len(guests)
	_ = json.NewEncoder(w).Encode(state)
}

func loadGuestSnapshot() []map[string]any {
	statePath := filepath.Join(runtimeDir(), "guest_snapshot.json")
	body, err := os.ReadFile(statePath)
	if err != nil {
		return []map[string]any{}
	}
	var guests []map[string]any
	if err := json.Unmarshal(body, &guests); err != nil {
		return []map[string]any{}
	}
	return guests
}

func openBrowser(url string) {
	switch runtime.GOOS {
	case "windows":
		_ = exec.Command("cmd", "/c", "start", "", url).Start()
	default:
		_ = exec.Command("xdg-open", url).Start()
	}
}
