"""Tests for output formatting and exports."""

from __future__ import annotations

import csv
import json
from pathlib import Path
from typing import Any

import pytest

from sb_scout.models import AppConfig, FilterConfig, DiskRequirements, BUILTIN_CPU_SPECS
from sb_scout.output import (
    build_markdown_report,
    build_summary,
    build_text_report,
    fmt_tb,
    money,
    row_tags,
    write_csv,
    write_json,
)
from sb_scout.scoring import apply_scores, build_rows, sort_rows


@pytest.fixture()
def scored_rows(sample_servers):
    cfg = AppConfig(filters=FilterConfig(ecc_only=False, disk=DiskRequirements()))
    rows, _ = build_rows(sample_servers, cfg, BUILTIN_CPU_SPECS)
    apply_scores(rows, cfg.weights)
    return rows


class TestHelpers:
    def test_money(self):
        assert money(42.7) == "€43"
        assert money(100.0) == "€100"

    def test_fmt_tb(self):
        assert fmt_tb(1000) == "1.00 TB"
        assert fmt_tb(500) == "0.50 TB"

    def test_row_tags_ecc_mixed(self):
        assert row_tags({"ecc": True, "has_inic": False, "has_gpu": False, "has_ssd": True, "has_hdd": True}) == "ECC, Mixed"

    def test_row_tags_ssd_only(self):
        assert row_tags({"ecc": False, "has_inic": False, "has_gpu": False, "has_ssd": True, "has_hdd": False}) == "SSD-only"

    def test_row_tags_gpu(self):
        assert row_tags({"ecc": False, "has_inic": False, "has_gpu": True, "has_ssd": False, "has_hdd": False}) == "GPU"

    def test_row_tags_empty(self):
        assert row_tags({"ecc": False, "has_inic": False, "has_gpu": False, "has_ssd": False, "has_hdd": False}) == "-"


class TestTextReport:
    def test_contains_header(self, scored_rows):
        cfg = AppConfig(filters=FilterConfig(ecc_only=False, disk=DiskRequirements()))
        tops = {
            "selected": scored_rows[:2],
            "cpu": scored_rows[:2],
            "storage": scored_rows[:2],
            "overall": scored_rows[:2],
        }
        report = build_text_report(
            config=cfg, feed_count=10, rows=scored_rows,
            sort_key="score_overall_rank", tops=tops,
        )
        assert "Hetzner" in report
        assert "Top" in report


class TestMarkdownReport:
    def test_contains_table(self, scored_rows):
        cfg = AppConfig(filters=FilterConfig(ecc_only=False, disk=DiskRequirements()))
        tops = {
            "selected": scored_rows[:2],
            "cpu": scored_rows[:2],
            "storage": scored_rows[:2],
            "overall": scored_rows[:2],
        }
        report = build_markdown_report(
            config=cfg, feed_count=10, rows=scored_rows,
            sort_key="score_overall_rank", tops=tops,
        )
        assert "| Rank |" in report
        assert "| ---" in report


class TestExports:
    def test_write_csv(self, scored_rows, tmp_path):
        p = tmp_path / "test.csv"
        write_csv(scored_rows, p)
        assert p.exists()
        with p.open() as f:
            reader = csv.DictReader(f)
            rows = list(reader)
        assert len(rows) == len(scored_rows)
        assert "id" in rows[0]

    def test_write_json(self, tmp_path):
        p = tmp_path / "test.json"
        data = {"key": "value", "num": 42}
        write_json(data, p)
        assert p.exists()
        loaded = json.loads(p.read_text())
        assert loaded == data


class TestBuildSummary:
    def test_structure(self, scored_rows):
        cfg = AppConfig(filters=FilterConfig(ecc_only=False, disk=DiskRequirements()))
        tops = {"selected": [], "cpu": [], "storage": [], "overall": []}
        s = build_summary(
            config=cfg, feed_count=10, rows=scored_rows,
            tops=tops, export_rows=scored_rows,
        )
        assert "source" in s
        assert "filters" in s
        assert "counts" in s
        assert s["counts"]["scored_servers"] == len(scored_rows)
