package doctor

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/steveyegge/beads/internal/beads"
	"github.com/steveyegge/beads/internal/configfile"
	"github.com/steveyegge/beads/internal/utils"
)

func CheckJSONLIntegrity(path string) DoctorCheck {
	// Follow redirect to resolve actual beads directory (bd-tvus fix)
	beadsDir := resolveBeadsDir(filepath.Join(path, ".beads"))

	// Resolve JSONL path.
	jsonlPath := ""
	if cfg, err := configfile.Load(beadsDir); err == nil && cfg != nil {
		if cfg.JSONLExport != "" && !isSystemJSONLFilename(cfg.JSONLExport) {
			p := cfg.JSONLPath(beadsDir)
			if _, err := os.Stat(p); err == nil {
				jsonlPath = p
			}
		}
	}
	if jsonlPath == "" {
		// Fall back to a best-effort discovery within .beads/.
		p := utils.FindJSONLInDir(beadsDir)
		if _, err := os.Stat(p); err == nil {
			jsonlPath = p
		}
	}
	if jsonlPath == "" {
		return DoctorCheck{Name: "JSONL Integrity", Status: StatusOK, Message: "N/A (no JSONL file)"}
	}

	// Best-effort scan for malformed lines.
	f, err := os.Open(jsonlPath) // #nosec G304 -- jsonlPath is within the workspace
	if err != nil {
		return DoctorCheck{
			Name:    "JSONL Integrity",
			Status:  StatusWarning,
			Message: "Unable to read JSONL file",
			Detail:  err.Error(),
		}
	}
	defer f.Close()

	var malformed int
	var examples []string
	scanner := bufio.NewScanner(f)
	lineNo := 0
	for scanner.Scan() {
		lineNo++
		line := strings.TrimSpace(scanner.Text())
		if line == "" {
			continue
		}
		var v struct {
			ID string `json:"id"`
		}
		if err := json.Unmarshal([]byte(line), &v); err != nil || v.ID == "" {
			malformed++
			if len(examples) < 5 {
				if err != nil {
					examples = append(examples, fmt.Sprintf("line %d: %v", lineNo, err))
				} else {
					examples = append(examples, fmt.Sprintf("line %d: missing id", lineNo))
				}
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return DoctorCheck{
			Name:    "JSONL Integrity",
			Status:  StatusWarning,
			Message: "Unable to scan JSONL file",
			Detail:  err.Error(),
		}
	}
	if malformed == 0 {
		return DoctorCheck{
			Name:    "JSONL Integrity",
			Status:  StatusOK,
			Message: fmt.Sprintf("%s looks valid", filepath.Base(jsonlPath)),
		}
	}

	// If we have a database, we can auto-repair by re-exporting from DB.
	dbPath := filepath.Join(beadsDir, beads.CanonicalDatabaseName)
	if cfg, err := configfile.Load(beadsDir); err == nil && cfg != nil && cfg.Database != "" {
		dbPath = cfg.DatabasePath(beadsDir)
	}
	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
		return DoctorCheck{
			Name:    "JSONL Integrity",
			Status:  StatusError,
			Message: fmt.Sprintf("%s has %d malformed line(s)", filepath.Base(jsonlPath), malformed),
			Detail:  strings.Join(examples, "\n"),
			Fix:     "Restore the JSONL file from git or from a backup (no database available for auto-repair).",
		}
	}

	return DoctorCheck{
		Name:    "JSONL Integrity",
		Status:  StatusError,
		Message: fmt.Sprintf("%s has %d malformed line(s)", filepath.Base(jsonlPath), malformed),
		Detail:  strings.Join(examples, "\n"),
		Fix:     "Run 'bd doctor --fix' to back up the JSONL and regenerate it from the database.",
	}
}

func isSystemJSONLFilename(name string) bool {
	switch name {
	case "deletions.jsonl", "interactions.jsonl", "molecules.jsonl":
		return true
	default:
		return false
	}
}
