package report

import (
	"encoding/json"
	"fmt"
	"io"
	"strings"
	"time"

	"arcline-audit/internal/types"
)

const sectionWidth = 55

// Terminal renders the audit result to the given writer in a human-readable terminal format.
func Terminal(w io.Writer, result types.AuditResult) {
	fmt.Fprintf(w, "\n")
	printSection(w, "SSL", result.SSL.Checks, func() {
		if result.SSL.Expiry != (time.Time{}) {
			fmt.Fprintf(w, "  Issuer     %s\n", result.SSL.Issuer)
			fmt.Fprintf(w, "  Expires    %s (%d days)\n",
				result.SSL.Expiry.Format("2006-01-02"), result.SSL.DaysLeft)
			if result.SSL.TLSVersion != "" {
				fmt.Fprintf(w, "  TLS        %s\n", result.SSL.TLSVersion)
			}
		}
	})

	printSection(w, "HTTP", result.HTTP.Checks, func() {
		if result.HTTP.FinalURL != "" {
			fmt.Fprintf(w, "  Final URL  %s\n", result.HTTP.FinalURL)
		}
		fmt.Fprintf(w, "  Response   %dms\n", result.HTTP.ResponseTime.Milliseconds())
	})

	printSection(w, "DNS", result.DNS.Checks, nil)
	printSection(w, "Infrastructure", result.Infra.Checks, func() {
		if result.Infra.CDN != "" {
			fmt.Fprintf(w, "  CDN        %s\n", result.Infra.CDN)
		}
		if result.Infra.ASN != "" {
			fmt.Fprintf(w, "  ASN        %s\n", result.Infra.ASN)
		}
		if result.Infra.Org != "" {
			fmt.Fprintf(w, "  Org        %s\n", result.Infra.Org)
		}
	})

	fmt.Fprintf(w, "\n")
}

// JSON renders the audit result as indented JSON.
func JSON(w io.Writer, result types.AuditResult) {
	enc := json.NewEncoder(w)
	enc.SetIndent("", "  ")
	enc.Encode(result)
}

// PlainText renders the audit result as plain text (no ANSI codes).
func PlainText(w io.Writer, result types.AuditResult) {
	sections := []struct {
		name   string
		checks []types.CheckResult
	}{
		{"SSL", result.SSL.Checks},
		{"HTTP", result.HTTP.Checks},
		{"DNS", result.DNS.Checks},
		{"Infrastructure", result.Infra.Checks},
	}

	fmt.Fprintf(w, "Audit for %s — %s\n\n", result.Domain, result.Time.Format(time.RFC3339))

	for _, sec := range sections {
		fmt.Fprintf(w, "── %s %s\n", sec.name, strings.Repeat("─", sectionWidth-5-len(sec.name)))
		for _, c := range sec.checks {
			fmt.Fprintf(w, "[%s] %s\n", c.Status, c.Message)
		}
		fmt.Fprintf(w, "\n")
	}
}

func printSection(w io.Writer, name string, checks []types.CheckResult, extra func()) {
	header := fmt.Sprintf("── %s ", name)
	fmt.Fprintf(w, "  %s%s\n", header, strings.Repeat("─", sectionWidth-len(header)-2))

	for _, c := range checks {
		prefix := statusPrefix(c.Status)
		fmt.Fprintf(w, "  %s %s\n", prefix, c.Message)
	}

	if extra != nil {
		extra()
	}
}

func statusPrefix(s types.Status) string {
	switch s {
	case types.StatusOK:
		return "[OK]  "
	case types.StatusWarn:
		return "[WARN]"
	case types.StatusFail:
		return "[FAIL]"
	case types.StatusInfo:
		return "[INFO]"
	default:
		return "[????]"
	}
}

