package main

import (
	"context"
	"flag"
	"fmt"
	"log/slog"
	"os"

	"github.com/jackc/pgx/v5/pgxpool"

	"github.com/ultisuite/ulti-backend/internal/api/mail"
	"github.com/ultisuite/ulti-backend/internal/dbmigrate"
	"github.com/ultisuite/ulti-backend/internal/envexpand"
	"github.com/ultisuite/ulti-backend/internal/mail/sanitize"
)

func main() {
	accountID := flag.String("account", "", "mail account UUID (optional; all accounts if empty)")
	dryRun := flag.Bool("dry-run", false, "scan only, do not write updates")
	flag.Parse()

	for _, path := range []string{".env", "../.env"} {
		_ = envexpand.ApplyFile(path)
	}

	dbURL := os.Getenv("DATABASE_URL")
	if dbURL == "" {
		slog.Error("DATABASE_URL is required")
		os.Exit(1)
	}

	ctx := context.Background()
	if err := dbmigrate.Up(dbURL); err != nil {
		slog.Error("migration failed", "error", err)
		os.Exit(1)
	}

	pool, err := pgxpool.New(ctx, dbURL)
	if err != nil {
		slog.Error("db connect failed", "error", err)
		os.Exit(1)
	}
	defer pool.Close()

	if *dryRun {
		scanned, changed, err := scanBodies(ctx, pool, *accountID)
		if err != nil {
			slog.Error("scan failed", "error", err)
			os.Exit(1)
		}
		fmt.Printf("dry-run: scanned=%d would_update=%d\n", scanned, changed)
		return
	}

	if *accountID != "" {
		svc := mail.NewService(pool, nil, nil, nil, "")
		result, err := svc.ResanitizeAccountBodiesByID(ctx, *accountID)
		if err != nil {
			slog.Error("resanitize failed", "account_id", *accountID, "error", err)
			os.Exit(1)
		}
		fmt.Printf("account=%s scanned=%d updated=%d\n", *accountID, result.Scanned, result.Updated)
		return
	}

	rows, err := pool.Query(ctx, `SELECT id FROM mail_accounts WHERE is_active = true ORDER BY created_at`)
	if err != nil {
		slog.Error("list accounts failed", "error", err)
		os.Exit(1)
	}
	defer rows.Close()

	svc := mail.NewService(pool, nil, nil, nil, "")
	var totalScanned, totalUpdated int
	for rows.Next() {
		var id string
		if err := rows.Scan(&id); err != nil {
			slog.Error("scan account id failed", "error", err)
			os.Exit(1)
		}
		result, err := svc.ResanitizeAccountBodiesByID(ctx, id)
		if err != nil {
			slog.Error("resanitize failed", "account_id", id, "error", err)
			os.Exit(1)
		}
		fmt.Printf("account=%s scanned=%d updated=%d\n", id, result.Scanned, result.Updated)
		totalScanned += result.Scanned
		totalUpdated += result.Updated
	}
	if err := rows.Err(); err != nil {
		slog.Error("list accounts failed", "error", err)
		os.Exit(1)
	}
	fmt.Printf("done: accounts scanned_messages=%d updated=%d\n", totalScanned, totalUpdated)
}

func scanBodies(ctx context.Context, pool *pgxpool.Pool, accountID string) (scanned, changed int, err error) {
	query := `
		SELECT id, body_html FROM messages
		WHERE body_html <> ''`
	args := []any{}
	if accountID != "" {
		query += ` AND account_id = $1`
		args = append(args, accountID)
	}

	rows, err := pool.Query(ctx, query, args...)
	if err != nil {
		return 0, 0, err
	}
	defer rows.Close()

	for rows.Next() {
		var id, body string
		if err := rows.Scan(&id, &body); err != nil {
			return scanned, changed, err
		}
		scanned++
		if sanitize.SanitizeHTML(body) != body {
			changed++
		}
	}
	return scanned, changed, rows.Err()
}
