import json
import tempfile
import unittest
from pathlib import Path

from post_import_refresh import AutomationConfig, StepResult, build_steps, write_status


class PostImportRefreshPlanTest(unittest.TestCase):
    def test_dry_run_is_the_default_and_never_enables_index_writes(self):
        config = AutomationConfig()
        steps = build_steps(config)
        commands = "\n".join(command for step in steps for command in step.commands)

        self.assertFalse(config.apply)
        self.assertIn("validate semantic index dry-run", [step.name for step in steps])
        self.assertIn("semantic_index/refresh.sh", commands)
        self.assertNotIn("semantic_index/refresh.sh --apply", commands)
        self.assertNotIn("--force-rebuild", commands)
        self.assertNotIn("systemctl enable --now semantic-index-refresh.timer", commands)

    def test_plugin_reapply_happens_before_migrations_and_helpdesk_reset(self):
        names = [step.name for step in build_steps(AutomationConfig())]

        self.assertLess(names.index("reapply tracked plugins"), names.index("run plugin migrations"))
        self.assertLess(names.index("run plugin migrations"), names.index("reset Helpdesk mail settings"))

    def test_expected_plugins_are_reapplied_to_remote_redmine_tree(self):
        steps = build_steps(AutomationConfig())
        plugin_step = next(step for step in steps if step.name == "reapply tracked plugins")
        commands = "\n".join(plugin_step.commands)

        self.assertIn("plugins/redmine_event_outbox", commands)
        self.assertIn("plugins/redmine_contacts", commands)
        self.assertIn("plugins/redmine_contacts_helpdesk", commands)
        self.assertNotIn("plugins/redmine_event_outbox/", commands)
        self.assertIn("reddev@192.168.50.170:/usr/share/redmine/plugins/", commands)

    def test_apply_mode_runs_mutating_validation_sequence(self):
        steps = build_steps(AutomationConfig(apply=True))
        commands = "\n".join(command for step in steps for command in step.commands)

        self.assertIn("bundle exec rake redmine:plugins:migrate", commands)
        self.assertIn("./reset_helpdesk_mail_settings.py", commands)
        self.assertIn("touch tmp/restart.txt", commands)
        self.assertIn("./validate_test_instance.py", commands)

    def test_remote_write_steps_use_sudo_by_default(self):
        commands = "\n".join(command for step in build_steps(AutomationConfig()) for command in step.commands)

        self.assertIn("--rsync-path 'sudo rsync'", commands)
        self.assertIn("sudo mkdir -p", commands)
        self.assertIn("sudo chmod -R g+rwX", commands)

    def test_local_mode_emits_local_commands_without_ssh(self):
        config = AutomationConfig(local=True)
        commands = "\n".join(command for step in build_steps(config) for command in step.commands)

        self.assertNotIn("ssh -i", commands)
        self.assertNotIn("rsync-path", commands)
        self.assertIn("reset_helpdesk_mail_settings.py --local", commands)
        self.assertIn("validate_test_instance.py --local", commands)
        self.assertNotIn("--composer-bin", commands)
        self.assertIn("redmine_outbox_worker.py --local --status", commands)
        self.assertIn("/opt/lanscratch/redmine-post-import/repo/plugins/redmine_event_outbox", commands)
        self.assertIn("/usr/share/redmine/plugins/", commands)
        self.assertIn("cd /usr/share/redmine && RAILS_ENV=production bundle exec rake redmine:plugins:migrate", commands)

    def test_local_semantic_check_is_non_blocking_without_staged_venv(self):
        config = AutomationConfig(local=True)
        semantic_step = next(step for step in build_steps(config) if step.name == "validate semantic index dry-run")
        command = semantic_step.commands[0]

        self.assertIn("test -x /opt/lanscratch/redmine-post-import/repo/.venv/bin/python", command)
        self.assertIn("semantic index runtime missing; skipping dry-run", command)
        self.assertIn("else", command)

    def test_status_paths_default_to_lanscratch(self):
        config = AutomationConfig()

        self.assertEqual(Path("/opt/lanscratch/redmine-post-import/status"), config.status_dir)

    def test_write_status_updates_latest_and_success_only_on_success(self):
        with tempfile.TemporaryDirectory() as tmp:
            config = AutomationConfig(status_dir=Path(tmp))
            failed = write_status(
                config,
                run_id="20260428T010000Z",
                status="failed",
                results=[StepResult("preflight", "test -d missing", 1)],
                failed_step="preflight",
            )

            self.assertTrue((Path(tmp) / "latest.json").exists())
            self.assertTrue((Path(tmp) / "runs" / "20260428T010000Z.json").exists())
            self.assertFalse((Path(tmp) / "latest-success.json").exists())
            self.assertEqual("failed", failed["status"])

            successful = write_status(
                config,
                run_id="20260428T010100Z",
                status="success",
                results=[StepResult("preflight", "test -d plugins", 0)],
            )

            latest_success = json.loads((Path(tmp) / "latest-success.json").read_text())
            self.assertEqual(successful["run_id"], latest_success["run_id"])
            self.assertEqual("success", latest_success["status"])


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