from __future__ import annotations

import json
import tempfile
import unittest
from pathlib import Path

from scope_harvest.config import assert_authorized, load_config
from scope_harvest.parser import SnapshotStructureError, parse_snapshot
from scope_harvest.runner import run_snapshot


class ParserTests(unittest.TestCase):
    def test_parses_fixed_snapshot(self) -> None:
        html = Path("samples/source_snapshot.html").read_text(encoding="utf-8")
        records = parse_snapshot(html, "2026-07-18T00:00:00Z", "version-1")
        self.assertEqual(len(records), 2)
        self.assertEqual(records[0].record_id, "notice-2026-001")
        self.assertEqual(records[1].published_at, "2026-07-08")

    def test_structure_change_raises_alert(self) -> None:
        html = Path("samples/broken_snapshot.html").read_text(encoding="utf-8")
        with self.assertRaisesRegex(SnapshotStructureError, "缺少字段"):
            parse_snapshot(html, "2026-07-18T00:00:00Z", "version-1")


class RunnerTests(unittest.TestCase):
    def write_config(
        self, root: Path, *, authorized: bool, prefix: str = "snapshot://authorized-demo/"
    ) -> Path:
        source = (Path.cwd() / "samples/source_snapshot.html").resolve()
        value = {
            "customer": "授权测试客户",
            "legal_purpose": "授权测试",
            "authorization_confirmed": authorized,
            "source_type": "snapshot",
            "source_path": str(source),
            "allowed_source_prefixes": [prefix],
            "allowed_fields": [
                "record_id",
                "title",
                "published_at",
                "source_url",
                "captured_at",
                "source_version",
            ],
            "max_pages": 3,
            "max_runtime_seconds": 60,
            "requests_per_minute": 12,
            "user_agent": "ScopeHarvest test",
            "output_format": "json",
            "timezone": "UTC",
        }
        path = root / "config.json"
        path.write_text(json.dumps(value), encoding="utf-8")
        return path

    def test_unconfirmed_authorization_refuses_run(self) -> None:
        with tempfile.TemporaryDirectory() as directory:
            config = load_config(self.write_config(Path(directory), authorized=False))
            with self.assertRaisesRegex(PermissionError, "授权未确认"):
                assert_authorized(config)

    def test_dry_run_writes_only_report(self) -> None:
        with tempfile.TemporaryDirectory() as directory:
            root = Path(directory)
            config = load_config(self.write_config(root, authorized=True))
            assert_authorized(config)
            report = run_snapshot(
                config,
                root / "records.json",
                root / "state.json",
                root / "report.json",
                dry_run=True,
                max_pages=3,
                max_runtime_seconds=60,
                stop_file=None,
            )
            self.assertEqual(report.status, "dry_run_completed")
            self.assertFalse((root / "records.json").exists())
            self.assertFalse((root / "state.json").exists())
            self.assertTrue((root / "report.json").exists())

    def test_resume_state_prevents_duplicates(self) -> None:
        with tempfile.TemporaryDirectory() as directory:
            root = Path(directory)
            config = load_config(self.write_config(root, authorized=True))
            assert_authorized(config)
            first = run_snapshot(
                config,
                root / "records.json",
                root / "state.json",
                root / "first.json",
                dry_run=False,
                max_pages=3,
                max_runtime_seconds=60,
                stop_file=None,
            )
            second = run_snapshot(
                config,
                root / "again.json",
                root / "state.json",
                root / "second.json",
                dry_run=False,
                max_pages=3,
                max_runtime_seconds=60,
                stop_file=None,
            )
            self.assertEqual(first.record_count, 2)
            self.assertEqual(second.record_count, 0)
            self.assertEqual(second.duplicate_count, 2)

    def test_out_of_scope_records_are_not_written(self) -> None:
        with tempfile.TemporaryDirectory() as directory:
            root = Path(directory)
            config = load_config(
                self.write_config(root, authorized=True, prefix="snapshot://other/")
            )
            assert_authorized(config)
            report = run_snapshot(
                config,
                root / "records.json",
                root / "state.json",
                root / "report.json",
                dry_run=False,
                max_pages=3,
                max_runtime_seconds=60,
                stop_file=None,
            )
            self.assertEqual(report.record_count, 0)
            self.assertEqual(report.parse_failures, 2)


if __name__ == "__main__":
    unittest.main()
