package ui

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"sort"
	"strings"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/widget"
)

// ShowBulkExportDialog opens a popup allowing the user to select
// one or more snapshots for export (JSON / CSV / HTML).
func ShowBulkExportDialog(w fyne.Window, snapshots []Snapshot) {

	if len(snapshots) == 0 {
		dialog.ShowInformation("Export", "No snapshots available.", w)
		return
	}

	// sort ascending by TS for stable ordering
	sort.Slice(snapshots, func(i, j int) bool {
		return snapshots[i].TS.Before(snapshots[j].TS)
	})

	// track selection state
	selected := make(map[int]bool)

	// build checkbox list
	rows := make([]fyne.CanvasObject, 0, len(snapshots))

	for i, s := range snapshots {
		idx := i
		label := fmt.Sprintf(
			"%s | CPU %.1f%% | RAM %.1f%% | DN %.0f B/s | UP %.0f B/s",
			s.TS.Format("2006-01-02 15:04:05"),
			s.CPU,
			s.RAM,
			s.NetDownBps,
			s.NetUpBps,
		)

		check := widget.NewCheck(label, func(v bool) {
			selected[idx] = v
		})

		rows = append(rows, check)
	}

	listBox := container.NewVBox(rows...)
	scroll := container.NewVScroll(listBox)
	scroll.SetMinSize(fyne.NewSize(750, 420))

	// helper to collect selected snapshots
	getSelected := func() []Snapshot {
		var out []Snapshot
		for i, ok := range selected {
			if ok {
				out = append(out, snapshots[i])
			}
		}
		return out
	}

	// select all
	selectAllBtn := widget.NewButton("Select All", func() {
		for i := range snapshots {
			selected[i] = true
		}
		for _, obj := range rows {
			if c, ok := obj.(*widget.Check); ok {
				c.SetChecked(true)
			}
		}
	})

	// clear selection
	clearBtn := widget.NewButton("Clear", func() {
		for i := range snapshots {
			selected[i] = false
		}
		for _, obj := range rows {
			if c, ok := obj.(*widget.Check); ok {
				c.SetChecked(false)
			}
		}
	})

	// -------------------------
	// Export JSON
	// -------------------------
	exportJSON := widget.NewButton("Export JSON", func() {
		data := getSelected()
		if len(data) == 0 {
			dialog.ShowInformation("Export", "No snapshots selected.", w)
			return
		}

		d := dialog.NewFileSave(func(uc fyne.URIWriteCloser, err error) {
			if err != nil || uc == nil {
				return
			}
			defer uc.Close()

			enc := json.NewEncoder(uc)
			enc.SetIndent("", "  ")
			_ = enc.Encode(data)
		}, w)

		// filename uses export time for series safety
		d.SetFileName(fmt.Sprintf(
			"sysmon_snapshots_%s.json",
			time.Now().Format("20060102_150405"),
		))
		d.Show()
	})

	// -------------------------
	// Export CSV
	// -------------------------
	exportCSV := widget.NewButton("Export CSV", func() {
		data := getSelected()
		if len(data) == 0 {
			dialog.ShowInformation("Export", "No snapshots selected.", w)
			return
		}

		flatten := func(s string) string {
			s = strings.ReplaceAll(s, "\r\n", "\n")
			s = strings.ReplaceAll(s, "\n", " | ")
			s = strings.Join(strings.Fields(s), " ")
			return s
		}

		d := dialog.NewFileSave(func(uc fyne.URIWriteCloser, err error) {
			if err != nil || uc == nil {
				return
			}
			defer uc.Close()

			wr := csv.NewWriter(uc)
			_ = wr.Write([]string{
				"ts",
				"cpu_pct",
				"ram_pct",
				"net_up_bps",
				"net_down_bps",
				"profile_json",
				"profile_text",
			})

			for _, s := range data {
				_ = wr.Write([]string{
					s.TS.Format(time.RFC3339),
					fmt.Sprintf("%.3f", s.CPU),
					fmt.Sprintf("%.3f", s.RAM),
					fmt.Sprintf("%.0f", s.NetUpBps),
					fmt.Sprintf("%.0f", s.NetDownBps),
					string(mustJSON(s.Profile)),
					flatten(s.ProfileText),
				})
			}

			wr.Flush()
		}, w)

		d.SetFileName(fmt.Sprintf(
			"sysmon_snapshots_%s.csv",
			time.Now().Format("20060102_150405"),
		))
		d.Show()
	})

	// -------------------------
	// Export HTML
	// -------------------------
	exportHTML := widget.NewButton("Export HTML", func() {
	data := getSelected()
	if len(data) == 0 {
		dialog.ShowInformation("Export", "No snapshots selected.", w)
		return
	}

	d := dialog.NewFileSave(func(uc fyne.URIWriteCloser, err error) {
		if err != nil || uc == nil {
			return
		}
		defer uc.Close()

		var b strings.Builder

		b.WriteString("<!doctype html><html><head><meta charset='utf-8'>")
		b.WriteString("<title>SysMon Snapshots</title>")
		b.WriteString("<style>")
		b.WriteString("body{font-family:system-ui,Segoe UI,Arial;background:#0c0c0e;color:#e6e6e6;padding:16px}")
		b.WriteString("table{border-collapse:collapse;width:100%;margin-top:12px}")
		b.WriteString("th,td{border:1px solid #333;padding:8px;text-align:left;vertical-align:top}")
		b.WriteString("th{background:#111217}")
		b.WriteString("pre{background:#111217;border:1px solid #333;padding:12px;white-space:pre-wrap}")
		b.WriteString(".section{margin-top:32px;padding-top:16px;border-top:2px solid #333}")
		b.WriteString(".accent{color:#00ffc6}")
		b.WriteString("</style></head><body>")

		b.WriteString("<h1>" + htmlEscape(AppTitle) + " Snapshots</h1>")
		b.WriteString("<div class='accent'>Exported: " + time.Now().Format("2006-01-02 15:04:05") + "</div>")

		// ===============================
		// SUMMARY TABLE
		// ===============================
		b.WriteString("<h2>Summary</h2>")
		b.WriteString("<table><thead><tr>")
		b.WriteString("<th>Timestamp</th><th>CPU %</th><th>RAM %</th><th>Net Down</th><th>Net Up</th>")
		b.WriteString("</tr></thead><tbody>")

		for _, s := range data {
			b.WriteString("<tr>")
			b.WriteString("<td>" + s.TS.Format("2006-01-02 15:04:05") + "</td>")
			b.WriteString(fmt.Sprintf("<td>%.2f</td>", s.CPU))
			b.WriteString(fmt.Sprintf("<td>%.2f</td>", s.RAM))
			b.WriteString(fmt.Sprintf("<td>%.0f</td>", s.NetDownBps))
			b.WriteString(fmt.Sprintf("<td>%.0f</td>", s.NetUpBps))
			b.WriteString("</tr>")
		}

		b.WriteString("</tbody></table>")

		// ===============================
		// DETAILED SECTIONS
		// ===============================
		b.WriteString("<h2>Detailed Snapshots</h2>")

		for _, s := range data {

			b.WriteString("<div class='section'>")
			b.WriteString("<h3>Snapshot: " + s.TS.Format("2006-01-02 15:04:05") + "</h3>")

			b.WriteString("<p>")
			b.WriteString(fmt.Sprintf(
				"<strong>CPU:</strong> %.2f%% &nbsp; | &nbsp; <strong>RAM:</strong> %.2f%% &nbsp; | &nbsp; <strong>Net Down:</strong> %.0f B/s &nbsp; | &nbsp; <strong>Net Up:</strong> %.0f B/s",
				s.CPU, s.RAM, s.NetDownBps, s.NetUpBps,
			))
			b.WriteString("</p>")

			// Structured JSON profile
			if len(s.Profile) > 0 {
				b.WriteString("<h4>Structured Profile</h4>")
				profileJSON, _ := json.MarshalIndent(s.Profile, "", "  ")
				b.WriteString("<pre>" + htmlEscape(string(profileJSON)) + "</pre>")
			}

			// Raw profile text
			if s.ProfileText != "" {
				b.WriteString("<h4>Raw Profile Text</h4>")
				b.WriteString("<pre>" + htmlEscape(s.ProfileText) + "</pre>")
			}

			b.WriteString("</div>")
		}

		b.WriteString("</body></html>")

		_, _ = uc.Write([]byte(b.String()))
	}, w)

	d.SetFileName(fmt.Sprintf(
		"sysmon_snapshots_%s.html",
		time.Now().Format("20060102_150405"),
	))
	d.Show()
})

	content := container.NewBorder(
		nil,
		container.NewHBox(selectAllBtn, clearBtn, exportJSON, exportCSV, exportHTML),
		nil,
		nil,
		scroll,
	)

	dialog.ShowCustom("Bulk Export Snapshots", "Close", content, w)
}

