// dbdiag inspects HamLog DB state. Optional 2nd arg: "wb CALL DXCC".
package main

import (
	"context"
	"database/sql"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"

	_ "modernc.org/sqlite"
)

const migrationsDir = "internal/db/migrations"

func main() {
	base, _ := os.UserConfigDir()
	dbPath := filepath.Join(base, "HamLog", "hamlog.db")

	mode := "summary"
	var call string
	var dxcc int
	if len(os.Args) >= 3 && os.Args[1] == "wb" {
		mode = "wb"
		call = strings.ToUpper(os.Args[2])
		if len(os.Args) >= 4 {
			dxcc, _ = strconv.Atoi(os.Args[3])
		}
	}

	fmt.Println("DB path:", dbPath)
	dsn := "file:" + dbPath + "?_pragma=foreign_keys(on)"
	conn, err := sql.Open("sqlite", dsn)
	must("open", err)
	defer conn.Close()
	must("ping", conn.Ping())

	if mode == "wb" {
		probeWB(conn, call, dxcc)
		probeCache(conn, call)
		return
	}
	summary(conn)
}

func probeCache(conn *sql.DB, call string) {
	fmt.Println("\nCache row for", call, ":")
	row := conn.QueryRow(`SELECT name, qth, country, grid, dxcc, source, fetched_at
                          FROM callsign_cache WHERE callsign = ?`, call)
	var name, qth, country, grid, src, fetched sql.NullString
	var dxcc sql.NullInt64
	if err := row.Scan(&name, &qth, &country, &grid, &dxcc, &src, &fetched); err != nil {
		fmt.Println("  (no cache row:", err, ")")
		return
	}
	fmt.Printf("  name=%q qth=%q country=%q grid=%q\n", name.String, qth.String, country.String, grid.String)
	fmt.Printf("  dxcc=%v(valid=%v) source=%s fetched_at=%s\n", dxcc.Int64, dxcc.Valid, src.String, fetched.String)
}

func probeWB(conn *sql.DB, call string, dxcc int) {
	fmt.Printf("\nProbing WorkedBefore for call=%q dxcc=%d\n", call, dxcc)

	var count int
	must("count call", conn.QueryRow(`SELECT COUNT(*) FROM qso WHERE callsign = ?`, call).Scan(&count))
	fmt.Printf("  count(callsign=%s) = %d\n", call, count)

	if dxcc == 0 {
		var d sql.NullInt64
		_ = conn.QueryRow(`SELECT dxcc FROM qso
            WHERE callsign = ? AND dxcc IS NOT NULL
            ORDER BY qso_date DESC LIMIT 1`, call).Scan(&d)
		if d.Valid {
			dxcc = int(d.Int64)
			fmt.Printf("  inferred dxcc from prior QSO: %d\n", dxcc)
		}
	}
	if dxcc == 0 {
		fmt.Println("  no DXCC available — skipping entity stats")
		return
	}

	var dxccCount int
	must("count dxcc", conn.QueryRow(`SELECT COUNT(*) FROM qso WHERE dxcc = ?`, dxcc).Scan(&dxccCount))
	fmt.Printf("  count(dxcc=%d) = %d\n", dxcc, dxccCount)

	// Distinct (band, mode) for this DXCC
	rows, err := conn.Query(`SELECT band, mode, COUNT(*) FROM qso WHERE dxcc = ? GROUP BY band, mode ORDER BY band, mode`, dxcc)
	must("group by band/mode", err)
	defer rows.Close()
	fmt.Printf("  distinct (band, mode) groups for dxcc=%d:\n", dxcc)
	var n int
	for rows.Next() {
		var band, mode string
		var c int
		rows.Scan(&band, &mode, &c)
		fmt.Printf("    %-8s %-12s %d QSOs\n", band, mode, c)
		n++
	}
	if n == 0 {
		fmt.Println("    (none)")
	}

	// Same query as backend
	fmt.Println("\n  --- exact backend query ---")
	rows2, err := conn.Query(`
        SELECT band, mode,
               MAX(CASE WHEN callsign = ? THEN 1 ELSE 0 END),
               MAX(CASE WHEN callsign = ?
                         AND (lotw_rcvd IN ('Y','V') OR qsl_rcvd IN ('Y','V') OR eqsl_rcvd IN ('Y','V'))
                        THEN 1 ELSE 0 END),
               MAX(CASE WHEN lotw_rcvd IN ('Y','V') OR qsl_rcvd IN ('Y','V') OR eqsl_rcvd IN ('Y','V')
                        THEN 1 ELSE 0 END)
        FROM qso WHERE dxcc = ?
        GROUP BY band, mode
        ORDER BY band, mode`, call, call, dxcc)
	must("backend query", err)
	defer rows2.Close()
	n = 0
	for rows2.Next() {
		var band, mode string
		var cw, cc, dc int
		rows2.Scan(&band, &mode, &cw, &cc, &dc)
		fmt.Printf("    %-8s %-12s callW=%d callC=%d dxccC=%d\n", band, mode, cw, cc, dc)
		n++
	}
	fmt.Printf("  → %d rows\n", n)
}

func summary(conn *sql.DB) {
	if st, err := os.Stat(filepath.Join(filepath.Dir(filepath.Dir(filepath.Dir(filepath.Dir("a")))), "")); err == nil {
		fmt.Printf("(size info skipped) %v\n", st)
	}

	fmt.Println("Applied migrations:")
	rows, err := conn.Query(`SELECT name FROM schema_migrations ORDER BY name`)
	if err == nil {
		for rows.Next() {
			var n string
			rows.Scan(&n)
			fmt.Println("  -", n)
		}
		rows.Close()
	}

	var n int64
	conn.QueryRow(`SELECT COUNT(*) FROM qso`).Scan(&n)
	fmt.Println("\nQSO rows:", n)

	var withDxcc int64
	conn.QueryRow(`SELECT COUNT(*) FROM qso WHERE dxcc IS NOT NULL`).Scan(&withDxcc)
	fmt.Printf("Rows with non-null dxcc: %d (%.1f%%)\n", withDxcc, float64(withDxcc)/float64(n)*100)

	var nDistinctDXCC int
	conn.QueryRow(`SELECT COUNT(DISTINCT dxcc) FROM qso WHERE dxcc IS NOT NULL`).Scan(&nDistinctDXCC)
	fmt.Println("Distinct DXCC entities in log:", nDistinctDXCC)

	fmt.Println("\nTry:  go run ./cmd/dbdiag wb 4X6TT")
	fmt.Println("      go run ./cmd/dbdiag wb 4X6TT 336")
	_ = context.Background
	_ = sort.Strings
	must("dummy", nil)
}

func must(label string, err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, label+":", err)
		os.Exit(1)
	}
}
