package webui

import (
	"encoding/json"
	"fmt"
	"html"
	"net/http"
	"os"
	"strings"
	"time"

	"bee/audit/internal/platform"
)

func (h *handler) handleTaskPage(w http.ResponseWriter, r *http.Request) {
	id := r.PathValue("id")
	task, ok := globalQueue.findByID(id)
	if !ok {
		http.NotFound(w, r)
		return
	}
	snapshot := *task
	body := renderTaskDetailPage(h.opts, snapshot)
	w.Header().Set("Cache-Control", "no-store")
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	_, _ = w.Write([]byte(body))
}

func (h *handler) handleAPITaskChartsIndex(w http.ResponseWriter, r *http.Request) {
	task, samples, _, _, ok := h.taskSamplesForRequest(r)
	if !ok {
		http.NotFound(w, r)
		return
	}
	type taskChartIndexEntry struct {
		Title string `json:"title"`
		File  string `json:"file"`
	}
	entries := make([]taskChartIndexEntry, 0)
	for _, spec := range taskChartSpecsForSamples(samples) {
		title, _, ok := renderTaskChartSVG(spec.Path, samples, taskTimelineForTask(task))
		if !ok {
			continue
		}
		entries = append(entries, taskChartIndexEntry{Title: title, File: spec.File})
	}
	w.Header().Set("Cache-Control", "no-store")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	_ = json.NewEncoder(w).Encode(entries)
}

func (h *handler) handleAPITaskChartSVG(w http.ResponseWriter, r *http.Request) {
	task, samples, _, _, ok := h.taskSamplesForRequest(r)
	if !ok {
		http.NotFound(w, r)
		return
	}
	file := strings.TrimPrefix(r.URL.Path, "/api/tasks/"+task.ID+"/chart/")
	path, ok := taskChartPathFromFile(file)
	if !ok {
		http.NotFound(w, r)
		return
	}
	title, buf, hasData := renderTaskChartSVG(path, samples, taskTimelineForTask(task))
	if !hasData || len(buf) == 0 || strings.TrimSpace(title) == "" {
		http.Error(w, "metrics history unavailable", http.StatusServiceUnavailable)
		return
	}
	w.Header().Set("Content-Type", "image/svg+xml")
	w.Header().Set("Cache-Control", "no-store")
	_, _ = w.Write(buf)
}

func renderTaskDetailPage(opts HandlerOptions, task Task) string {
	title := task.Name
	if strings.TrimSpace(title) == "" {
		title = task.ID
	}
	var body strings.Builder
	body.WriteString(`<div style="display:flex;align-items:center;gap:12px;margin-bottom:16px;flex-wrap:wrap">`)
	body.WriteString(`<a class="btn btn-secondary btn-sm" href="/tasks">Back to Tasks</a>`)
	if task.Status == TaskRunning || task.Status == TaskPending {
		body.WriteString(`<button class="btn btn-danger btn-sm" onclick="cancelTaskDetail('` + html.EscapeString(task.ID) + `')">Cancel</button>`)
	}
	body.WriteString(`<span style="font-size:12px;color:var(--muted)">Artifacts are saved in the task folder under <code>./tasks</code>.</span>`)
	body.WriteString(`</div>`)

	if report := loadTaskReportFragment(task); report != "" {
		body.WriteString(report)
	} else {
		body.WriteString(`<div class="card"><div class="card-head">Task Summary</div><div class="card-body">`)
		body.WriteString(`<div style="font-size:18px;font-weight:700">` + html.EscapeString(title) + `</div>`)
		body.WriteString(`<div style="margin-top:8px">` + renderTaskStatusBadge(task.Status) + `</div>`)
		if strings.TrimSpace(task.ErrMsg) != "" {
			body.WriteString(`<div style="margin-top:8px;color:var(--crit-fg)">` + html.EscapeString(task.ErrMsg) + `</div>`)
		}
		body.WriteString(`</div></div>`)
	}

	if task.Status == TaskRunning {
		body.WriteString(`<div class="card"><div class="card-head">Live Charts</div><div class="card-body">`)
		body.WriteString(`<div id="task-live-charts" style="display:flex;flex-direction:column;gap:16px;color:var(--muted);font-size:13px">Loading charts...</div>`)
		body.WriteString(`</div></div>`)
	}

	if task.Status == TaskRunning || task.Status == TaskPending {
		body.WriteString(`<div class="card"><div class="card-head">Live Logs</div><div class="card-body">`)
		body.WriteString(`<div id="task-live-log" class="terminal" style="max-height:none;white-space:pre-wrap">Connecting...</div>`)
		body.WriteString(`</div></div>`)
		body.WriteString(`<script>
function cancelTaskDetail(id) {
  fetch('/api/tasks/' + id + '/cancel', {method:'POST'}).then(function(){
    var term = document.getElementById('task-live-log');
    if (term) {
      term.textContent += '\nCancel requested.\n';
      term.scrollTop = term.scrollHeight;
    }
  });
}
function renderTaskLiveCharts(taskId, charts) {
  const host = document.getElementById('task-live-charts');
  if (!host) return;
  if (!Array.isArray(charts) || charts.length === 0) {
    host.innerHTML = 'Waiting for metric samples...';
    return;
  }
  const seen = {};
  charts.forEach(function(chart) {
    seen[chart.file] = true;
    let img = host.querySelector('img[data-chart-file="' + chart.file + '"]');
    if (img) {
      const card = img.closest('.card');
      if (card) {
        const title = card.querySelector('.card-head');
        if (title) title.textContent = chart.title;
      }
      return;
    }
    const card = document.createElement('div');
    card.className = 'card';
    card.style.margin = '0';
    card.innerHTML = '<div class="card-head"></div><div class="card-body" style="padding:12px"></div>';
    card.querySelector('.card-head').textContent = chart.title;
    const body = card.querySelector('.card-body');
    img = document.createElement('img');
    img.setAttribute('data-task-chart', '1');
    img.setAttribute('data-chart-file', chart.file);
    img.setAttribute('data-base-src', '/api/tasks/' + taskId + '/chart/' + chart.file);
    img.src = '/api/tasks/' + taskId + '/chart/' + chart.file + '?t=' + Date.now();
    img.style.width = '100%';
    img.style.display = 'block';
    img.style.borderRadius = '6px';
    img.alt = chart.title;
    body.appendChild(img);
    host.appendChild(card);
  });
  Array.from(host.querySelectorAll('img[data-task-chart="1"]')).forEach(function(img) {
    const file = img.getAttribute('data-chart-file') || '';
    if (seen[file]) return;
    const card = img.closest('.card');
    if (card) card.remove();
  });
}
function loadTaskLiveCharts(taskId) {
  fetch('/api/tasks/' + taskId + '/charts').then(function(r){ return r.json(); }).then(function(charts){
    renderTaskLiveCharts(taskId, charts);
  }).catch(function(){
    const host = document.getElementById('task-live-charts');
    if (host) host.innerHTML = 'Task charts are unavailable.';
  });
}
function refreshTaskLiveCharts() {
  document.querySelectorAll('img[data-task-chart="1"]').forEach(function(img){
    const base = img.dataset.baseSrc;
    if (!base) return;
    img.src = base + '?t=' + Date.now();
  });
}
var _taskDetailES = new EventSource('/api/tasks/` + html.EscapeString(task.ID) + `/stream');
var _taskDetailTerm = document.getElementById('task-live-log');
var _taskChartTimer = null;
var _taskChartsFrozen = false;
_taskDetailES.onopen = function(){ _taskDetailTerm.textContent = ''; };
_taskDetailES.onmessage = function(e){ _taskDetailTerm.textContent += e.data + "\n"; _taskDetailTerm.scrollTop = _taskDetailTerm.scrollHeight; };
_taskDetailES.addEventListener('done', function(e){
  if (_taskChartTimer) clearInterval(_taskChartTimer);
  _taskDetailES.close();
  _taskDetailES = null;
  _taskChartsFrozen = true;
  _taskDetailTerm.textContent += (e.data ? '\nTask finished with error.\n' : '\nTask finished.\n');
  _taskDetailTerm.scrollTop = _taskDetailTerm.scrollHeight;
  refreshTaskLiveCharts();
});
_taskDetailES.onerror = function(){
  if (_taskChartTimer) clearInterval(_taskChartTimer);
  if (_taskDetailES) {
    _taskDetailES.close();
    _taskDetailES = null;
  }
};
loadTaskLiveCharts('` + html.EscapeString(task.ID) + `');
_taskChartTimer = setInterval(function(){
  if (_taskChartsFrozen) return;
  loadTaskLiveCharts('` + html.EscapeString(task.ID) + `');
  refreshTaskLiveCharts();
}, 2000);
</script>`)
	}

	return layoutHead(opts.Title+" — "+title) +
		layoutNav("tasks", opts.BuildLabel) +
		`<div class="main"><div class="topbar"><h1>` + html.EscapeString(title) + `</h1></div><div class="content">` +
		body.String() +
		`</div></div></body></html>`
}

func loadTaskReportFragment(task Task) string {
	if strings.TrimSpace(task.ReportHTMLPath) == "" {
		return ""
	}
	data, err := os.ReadFile(task.ReportHTMLPath)
	if err != nil || len(data) == 0 {
		return ""
	}
	return string(data)
}

func taskArtifactDownloadLink(task Task, absPath string) string {
	if strings.TrimSpace(absPath) == "" {
		return ""
	}
	return fmt.Sprintf(`/export/file?path=%s`, absPath)
}

func (h *handler) taskSamplesForRequest(r *http.Request) (Task, []platform.LiveMetricSample, time.Time, time.Time, bool) {
	id := r.PathValue("id")
	taskPtr, ok := globalQueue.findByID(id)
	if !ok {
		return Task{}, nil, time.Time{}, time.Time{}, false
	}
	task := *taskPtr
	start, end := taskTimeWindow(&task)
	samples, err := loadTaskMetricSamples(start, end)
	if err != nil {
		return task, nil, start, end, true
	}
	return task, samples, start, end, true
}

func taskTimelineForTask(task Task) []chartTimelineSegment {
	start, end := taskTimeWindow(&task)
	return []chartTimelineSegment{{Start: start, End: end, Active: true}}
}

func taskChartPathFromFile(file string) (string, bool) {
	file = strings.TrimSpace(file)
	for _, spec := range taskDashboardChartSpecs {
		if spec.File == file {
			return spec.Path, true
		}
	}
	if strings.HasPrefix(file, "gpu-") && strings.HasSuffix(file, "-overview.svg") {
		id := strings.TrimSuffix(strings.TrimPrefix(file, "gpu-"), "-overview.svg")
		return "gpu/" + id + "-overview", true
	}
	return "", false
}
