"""audit.py 原型的契約測試：索引頁繼承與分層合併隔離。"""
import json
import os
import sys
import tempfile
import unittest

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import audit  # noqa: E402

HERE = os.path.dirname(os.path.abspath(__file__))
COMMON = os.path.join(HERE, 'registry.common.json')


def project_layer(tmp, data):
    path = os.path.join(tmp, 'registry.project.json')
    with open(path, 'w', encoding='utf-8') as f:
        json.dump({'schema': 1, 'layer': 'project', 'types': [], **data}, f)
    return path


def effective(f, paths, docs='x-docs'):
    compiled = audit.compile_types(audit.load_registry(paths), docs, [docs, 'x-server'])
    t, eff, leg, container, _ = audit.classify(f, compiled)
    return t, eff, leg, container


class InheritTest(unittest.TestCase):
    def test_review_evidence_index_keeps_temporary_policy(self):
        for name in ('README.md', '_category_.json'):
            t, eff, _, container = effective(f'x-docs/docs/exchanges/reviews/demo/evidence/{name}', [COMMON])
            self.assertTrue(t.get('inherit'))
            self.assertEqual(container['id'], 'peer-review-evidence')
            self.assertEqual((eff['lifecycle'], eff['retention'], eff['distribution']),
                             ('temporary', 'remove-at-close', 'preview-only'))

    def test_review_root_index_keeps_temporary_policy(self):
        for name in ('README.md', '_category_.json', 'notes.md'):
            t, eff, _, container = effective(f'x-docs/docs/exchanges/reviews/demo/{name}', [COMMON])
            owner = container or t
            self.assertEqual(owner['id'], 'peer-review-exchange', name)
            self.assertEqual((eff['lifecycle'], eff['retention'], eff['distribution']),
                             ('temporary', 'remove-at-close', 'preview-only'), name)

    def test_work_root_index_inherits_work_record(self):
        _, eff, _, container = effective('x-docs/docs/exchanges/work/w1/README.md', [COMMON])
        self.assertEqual(container['id'], 'work-evidence')
        self.assertEqual(eff['retention'], 'referenced')

    def test_temporary_type_without_container_fails_lint(self):
        types = audit.load_registry([COMMON])
        types = [t for t in types if t['id'] != 'peer-review-exchange']
        rules = {(i[0], i[1]) for i in audit.lint(types)}
        self.assertIn(('peer-review-brief', 'R11'), rules)

    def test_report_evidence_readme_keeps_retention(self):
        _, eff, _, container = effective('x-docs/docs/testing/reports/RPT-001/README.md', [COMMON])
        self.assertEqual(container['id'], 'report-evidence')
        self.assertEqual(eff['retention'], 'referenced+latest')

    def test_index_without_container_uses_own_values(self):
        t, eff, _, container = effective('x-docs/docs/specs/README.md', [COMMON])
        self.assertEqual(t['id'], 'section-index')
        self.assertIsNone(container)
        self.assertEqual((eff['lifecycle'], eff['distribution']), ('persistent', 'site'))


class LayerTest(unittest.TestCase):
    def test_project_defaults_do_not_touch_common_types(self):
        with tempfile.TemporaryDirectory() as tmp:
            proj = project_layer(tmp, {'defaults': {'retention': 'local-only', 'distribution': 'workspace', 'git': 'ignored'},
                                       'types': [{'id': 'p-note', 'title': 'x', 'category': 'other', 'role': 'document',
                                                  'paths': ['{docsRoot}/docs/notes/**'], 'lifecycle': 'persistent',
                                                  'writer': {'mode': 'open'}, 'presentation': 'page',
                                                  'base': 'other', 'purpose': 'x', 'gitReason': 'test'}]})
            types = {t['id']: t for t in audit.load_registry([COMMON, proj])}
            us = types['us']
            self.assertEqual((us['retention'], us['distribution'], us['_git']), ('all', 'site', 'tracked'))
            self.assertEqual(types['p-note']['retention'], 'local-only')

    def test_project_cannot_redefine_common_type(self):
        with tempfile.TemporaryDirectory() as tmp:
            proj = project_layer(tmp, {'types': [{'id': 'us', 'title': 'x', 'category': 'spec', 'role': 'document',
                                                  'paths': [], 'lifecycle': 'scratch', 'writer': {'mode': 'open'},
                                                  'presentation': 'hidden'}]})
            with self.assertRaises(audit.RegistryError):
                audit.load_registry([COMMON, proj])

    def test_extend_common_only_appends_legacy(self):
        with tempfile.TemporaryDirectory() as tmp:
            proj = project_layer(tmp, {'extendCommon': [{'id': 'us', 'legacy': ['{docsRoot}/docs/old-us/*.md']}]})
            t, _, leg, _ = effective('x-docs/docs/old-us/US-01.md', [COMMON, proj])
            self.assertEqual(t['id'], 'us')
            self.assertTrue(leg)
            bad = project_layer(tmp, {'extendCommon': [{'id': 'us', 'retention': 'local-only'}]})
            with self.assertRaises(audit.RegistryError):
                audit.load_registry([COMMON, bad])

    def test_common_registry_has_no_lint_issues(self):
        self.assertEqual(audit.lint(audit.load_registry([COMMON])), [])


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