from __future__ import annotations

import unittest
import shutil
from pathlib import Path
from uuid import uuid4

from mais_humana.acceptance import acceptance_markdown, build_acceptance_report
from mais_humana.models import ReportBundle
from mais_humana.redaction import redaction_markdown, redact_sensitive_text, scan_generated_artifacts, scan_text_for_secrets
from tests.helpers import make_tmp


class RedactionAcceptanceTests(unittest.TestCase):
    def make_scan_root(self) -> Path:
        root = Path.cwd() / "tmp-redaction-fixtures" / uuid4().hex
        root.mkdir(parents=True, exist_ok=False)
        return root

    def test_redaction_allows_references_but_flags_secret_values(self) -> None:
        text = """
credentialRef: safe-reference-only
token = "abcdefghijklmnopqrstuvwxyz1234567890"
Bearer abcdefghijklmnopqrstuvwxyz1234567890
"""
        findings = scan_text_for_secrets("sample.md", text)
        self.assertGreaterEqual(len(findings), 2)
        self.assertTrue(all(finding.path == "sample.md" for finding in findings))

    def test_redaction_scans_generated_text_files(self) -> None:
        root = self.make_scan_root()
        try:
            (root / "dados").mkdir()
            (root / "dados" / "ok.json").write_text('{"credentialRef":"abc"}', encoding="utf-8")
            (root / "dados" / "bad.md").write_text('password="abcdefghijklmnopqrstuvwxyz123456"', encoding="utf-8")
            report = scan_generated_artifacts(root)
        finally:
            shutil.rmtree(root, ignore_errors=True)
        self.assertFalse(report.passed)
        markdown = redaction_markdown(report)
        self.assertIn("achados", markdown)

    def test_redaction_ignores_hashes_and_test_tmp_outputs(self) -> None:
        root = self.make_scan_root()
        try:
            (root / "dados").mkdir()
            (root / ".test-tmp" / "case" / "dados").mkdir(parents=True)
            hash_only = "a" * 64
            (root / "dados" / "hash.json").write_text(f'{{"snapshotHash":"{hash_only}"}}', encoding="utf-8")
            (root / ".test-tmp" / "case" / "dados" / "bad.md").write_text(
                'password="abcdefghijklmnopqrstuvwxyz123456"',
                encoding="utf-8",
            )
            report = scan_generated_artifacts(root)
        finally:
            shutil.rmtree(root, ignore_errors=True)
        self.assertTrue(report.passed)

    def test_redaction_flags_contextual_cloudflare_token_values(self) -> None:
        findings = scan_text_for_secrets("env.txt", "cloudflare_token=abcdefghijklmnopqrstuvwxyz1234567890")
        self.assertEqual(len(findings), 1)
        self.assertEqual(findings[0].pattern_id, "cloudflare_token_assignment")
        self.assertNotIn("abcdefghijklmnopqrstuvwxyz", findings[0].sample)
        self.assertIn("[redacted:", findings[0].sample)

    def test_redaction_flags_cfat_even_when_named_as_reference(self) -> None:
        findings = scan_text_for_secrets("route.md", "tokenRef=cfat_abcdefghijklmnopqrstuvwxyz1234567890")
        self.assertEqual(len(findings), 1)
        self.assertEqual(findings[0].pattern_id, "cloudflare_cfat_token")
        self.assertEqual(findings[0].sample, "cfat_[redacted:41]")

    def test_redaction_allows_single_opaque_reference_line(self) -> None:
        findings = scan_text_for_secrets("route.md", "credentialRef: cf-token-prod-readonly")
        self.assertEqual(findings, ())

    def test_redact_sensitive_text_masks_known_secret_shapes(self) -> None:
        text = "Authorization: Bearer abcdefghijklmnopqrstuvwxyz1234567890\ncloudflare_token=abcdefghijklmnopqrstuvwxyz1234567890"
        redacted = redact_sensitive_text(text)
        self.assertNotIn("abcdefghijklmnopqrstuvwxyz1234567890", redacted)
        self.assertIn("[redacted:", redacted)

    def test_acceptance_report_handles_missing_artifacts(self) -> None:
        root = make_tmp()
        bundle = ReportBundle(
            output_root=str(root),
            generated_files=(),
            platform_count=0,
            profile_count=0,
            matrix_cells=0,
            total_code_lines_analyzed=0,
            warnings=(),
        )
        report = build_acceptance_report(root, (), (), bundle)
        self.assertFalse(report.passed)
        markdown = acceptance_markdown(report)
        self.assertIn("pendente", markdown)
        self.assertIn("Leitura tecnica minima", markdown)


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