"""Safety regressions for the verification harness itself (no API changes)."""
import json
from pathlib import Path
import sqlite3
import tempfile
import unittest
from unittest.mock import patch
import run


class IsolationTests(unittest.TestCase):
    def setUp(self):
        self.temp = tempfile.TemporaryDirectory()
        self.root = Path(self.temp.name)
        self.patch = patch.object(run, 'ROOT', self.root)
        self.patch.start()
        self.directory = self.root / ('E2E-' + 'a' * 16)
        self.directory.mkdir(mode=0o700)
        (self.directory / 'marker').write_text(self.directory.name)

    def tearDown(self):
        self.patch.stop()
        self.temp.cleanup()

    def test_marker_mismatch_refused(self):
        (self.directory / 'marker').write_text('wrong')
        with self.assertRaises(RuntimeError):
            run.guard(self.directory)

    def test_database_symlink_refused(self):
        (self.directory / 'database.sqlite').symlink_to(self.root / 'live.sqlite')
        with self.assertRaises(RuntimeError):
            run.guard(self.directory)

    def test_outside_directory_refused(self):
        with self.assertRaises(RuntimeError):
            run.guard(self.root.parent)

    def test_nonfixture_user_blocks_cleanup(self):
        db = self.directory / 'database.sqlite'
        with sqlite3.connect(db) as conn:
            conn.execute('CREATE TABLE users (name TEXT, email TEXT)')
            conn.execute('INSERT INTO users VALUES (?, ?)', ('Real Person', 'real@example.com'))
        with self.assertRaises(RuntimeError):
            run.cleanup(self.directory)
        self.assertTrue(db.exists())

    def test_exact_private_cleanup_and_evidence(self):
        db = self.directory / 'database.sqlite'
        with sqlite3.connect(db) as conn:
            conn.execute('CREATE TABLE users (name TEXT, email TEXT)')
            conn.execute('INSERT INTO users VALUES (?, ?)', (self.directory.name+' Staff', 'staff@example.test'))
        (self.directory / 'manifest.json').write_text('{}')
        (self.directory / 'evidence.json').write_text('{}')
        run.cleanup(self.directory)
        proof = json.loads((self.directory / 'cleanup.json').read_text())
        self.assertTrue(proof['database_absent'])
        self.assertTrue(proof['credentials_absent'])
        self.assertEqual(proof['counts_before']['users'], 1)
        self.assertTrue((self.directory / 'evidence.json').exists())

    def test_source_snapshot_detects_runtime_source_changes(self):
        (self.root / 'packages').mkdir()
        source = self.directory / 'source.ts'
        source.write_text('export const value = 1;')
        with patch.object(run, 'WEB', self.root), patch.object(run, 'API', self.root / 'api'), patch.object(run, 'HERE', self.directory):
            first = run.source_snapshot()
            source.write_text('export const value = 2;')
            second = run.source_snapshot()
        self.assertNotEqual(first['sha256'], second['sha256'])
        self.assertEqual(len(first['files']), 1)

    def test_source_snapshot_detects_runtime_config_and_contract_changes(self):
        (self.root / 'packages').mkdir()
        for relative in ('web/next.config.ts', 'package-lock.json', 'contracts/openapi.yaml', 'api/composer.lock'):
            with self.subTest(path=relative):
                config = self.root / relative
                config.parent.mkdir(parents=True, exist_ok=True)
                config.write_text('initial configuration')
                with patch.object(run, 'WEB', self.root), patch.object(run, 'API', self.root / 'api'), patch.object(run, 'HERE', self.directory):
                    first = run.source_snapshot()
                    config.write_text('changed configuration')
                    second = run.source_snapshot()
                self.assertNotEqual(first['sha256'], second['sha256'])
                self.assertIn(str(config.relative_to(self.root.parent)), first['files'])

    def test_environment_drops_external_credentials(self):
        with patch.dict('os.environ', {'STRIPE_SECRET_KEY': 'sentinel', 'DB_URL': 'mysql://unsafe'}):
            env = run.environment(self.directory, self.directory.name)
        self.assertNotIn('STRIPE_SECRET_KEY', env)
        self.assertEqual(env['DB_URL'], '')
        self.assertEqual(env['DB_DATABASE'], str(self.directory / 'database.sqlite'))
        self.assertEqual(env['MAIL_MAILER'], 'array')


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