# #region TestTranslateSchedulesIntegration [C:3] [TYPE Module] [SEMANTICS test,translate,schedule,integration]
# @BRIEF Integration tests for TranslationSchedule CRUD with real PostgreSQL via Testcontainers.
# @RELATION BINDS_TO -> [TranslationScheduler]
#
# @TEST_CONTRACT TranslationScheduler ->
#   create_schedule: job_id + cron + timezone -> TranslationSchedule persisted
#   get_schedule: job_id -> TranslationSchedule or ValueError
#   update_schedule: job_id + fields -> updated schedule
#   delete_schedule: job_id -> None (schedule removed)
#   set_schedule_active: job_id + is_active -> schedule toggled
#   get_next_executions: cron + tz + n -> list of ISO datetime strings
#   list_active_schedules: db -> list[TranslationSchedule]
#
# @TEST_EDGE: non_existent_job -> ValueError on create
# @TEST_EDGE: get_non_existent -> ValueError with "No schedule found"
# @TEST_EDGE: delete_non_existent -> ValueError
# @TEST_EDGE: update_non_existent -> ValueError
import pytest

from sqlalchemy.orm import Session

from src.models.translate import TranslationJob, TranslationSchedule
from src.plugins.translate.scheduler import TranslationScheduler


# #region TestScheduleCRUD [C:3] [TYPE Class]
# @BRIEF Integration tests for schedule CRUD operations with real PostgreSQL.
class TestScheduleCRUD:
    """Verify TranslationScheduler CRUD with real PostgreSQL."""

    def _create_job(self, db: Session, status: str = "DRAFT") -> TranslationJob:
        job = TranslationJob(
            name="Test Job",
            status=status,
            source_dialect="postgresql",
            target_dialect="clickhouse",
            created_by="test_user",
        )
        db.add(job)
        db.commit()
        db.refresh(job)
        return job

    # #region test_create_schedule [C:2] [TYPE Function]
    def test_create_schedule(self, db_session: Session, mock_config_manager):
        job = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)

        sched = scheduler.create_schedule(
            job_id=job.id,
            cron_expression="0 2 * * *",
            timezone="Europe/Moscow",
            execution_mode="new_key_only",
        )

        assert sched.job_id == job.id
        assert sched.cron_expression == "0 2 * * *"
        assert sched.timezone == "Europe/Moscow"
        assert sched.execution_mode == "new_key_only"
        assert sched.is_active is True
    # #endregion test_create_schedule

    # #region test_create_schedule_full_mode_default [C:2] [TYPE Function]
    def test_create_schedule_full_mode_default(self, db_session: Session, mock_config_manager):
        job = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        sched = scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *")
        assert sched.execution_mode == "full"
    # #endregion test_create_schedule_full_mode_default

    # #region test_get_schedule [C:2] [TYPE Function]
    def test_get_schedule(self, db_session: Session, mock_config_manager):
        job = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *")
        db_session.commit()

        result = scheduler.get_schedule(job.id)
        assert result is not None
        assert result.cron_expression == "0 2 * * *"
    # #endregion test_get_schedule

    # #region test_get_schedule_no_schedule [C:2] [TYPE Function]
    def test_get_schedule_no_schedule(self, db_session: Session, mock_config_manager):
        job = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        with pytest.raises(ValueError, match="No schedule found"):
            scheduler.get_schedule(job.id)
    # #endregion test_get_schedule_no_schedule

    # #region test_update_schedule_all_fields [C:2] [TYPE Function]
    def test_update_schedule_all_fields(self, db_session: Session, mock_config_manager):
        job = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *")
        db_session.commit()

        updated = scheduler.update_schedule(
            job_id=job.id, cron_expression="30 6 * * 1",
            timezone_str="Asia/Tokyo", is_active=False,
            execution_mode="full",
        )
        assert updated.cron_expression == "30 6 * * 1"
        assert updated.timezone == "Asia/Tokyo"
        assert updated.is_active is False
        assert updated.execution_mode == "full"
    # #endregion test_update_schedule_all_fields

    # #region test_update_schedule_partial [C:2] [TYPE Function]
    def test_update_schedule_partial(self, db_session: Session, mock_config_manager):
        job = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *", timezone="Europe/Moscow")
        db_session.commit()

        updated = scheduler.update_schedule(job_id=job.id, cron_expression="0 4 * * *")
        assert updated.cron_expression == "0 4 * * *"
        assert updated.timezone == "Europe/Moscow"
    # #endregion test_update_schedule_partial

    # #region test_delete_schedule [C:2] [TYPE Function]
    def test_delete_schedule(self, db_session: Session, mock_config_manager):
        job = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *")
        db_session.commit()

        scheduler.delete_schedule(job.id)
        with pytest.raises(ValueError, match="No schedule found"):
            scheduler.get_schedule(job.id)
    # #endregion test_delete_schedule

    # #region test_set_schedule_active [C:2] [TYPE Function]
    def test_set_schedule_active(self, db_session: Session, mock_config_manager):
        job = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *", is_active=False)
        db_session.commit()

        sched = scheduler.set_schedule_active(job.id, True)
        assert sched.is_active is True

        sched = scheduler.set_schedule_active(job.id, False)
        assert sched.is_active is False
    # #endregion test_set_schedule_active

    # #region test_set_schedule_active_twice [C:2] [TYPE Function]
    def test_set_schedule_active_twice(self, db_session: Session, mock_config_manager):
        job = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        scheduler.create_schedule(job_id=job.id, cron_expression="0 2 * * *")
        db_session.commit()

        sched = scheduler.set_schedule_active(job.id, True)
        assert sched.is_active is True
        sched = scheduler.set_schedule_active(job.id, True)
        assert sched.is_active is True
    # #endregion test_set_schedule_active_twice

    # #region test_create_schedule_non_existent_job [C:2] [TYPE Function]
    def test_create_schedule_non_existent_job(self, db_session: Session, mock_config_manager):
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        with pytest.raises(ValueError, match="not found"):
            scheduler.create_schedule(job_id="non-existent-id", cron_expression="0 2 * * *")
    # #endregion test_create_schedule_non_existent_job

    # #region test_delete_schedule_non_existent [C:2] [TYPE Function]
    def test_delete_schedule_non_existent(self, db_session: Session, mock_config_manager):
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        with pytest.raises(ValueError, match="No schedule found"):
            scheduler.delete_schedule(job_id="non-existent-id")
    # #endregion test_delete_schedule_non_existent

    # #region test_update_schedule_no_schedule [C:2] [TYPE Function]
    def test_update_schedule_no_schedule(self, db_session: Session, mock_config_manager):
        job = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        with pytest.raises(ValueError, match="No schedule found"):
            scheduler.update_schedule(job_id=job.id, cron_expression="0 2 * * *")
    # #endregion test_update_schedule_no_schedule

    # #region test_set_active_non_existent [C:2] [TYPE Function]
    def test_set_active_non_existent(self, db_session: Session, mock_config_manager):
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        with pytest.raises(ValueError, match="No schedule found"):
            scheduler.set_schedule_active(job_id="non-existent", is_active=True)
    # #endregion test_set_active_non_existent

    # #region test_list_active_schedules [C:2] [TYPE Function]
    def test_list_active_schedules(self, db_session: Session, mock_config_manager):
        job1 = self._create_job(db_session)
        job2 = self._create_job(db_session)
        scheduler = TranslationScheduler(db_session, mock_config_manager)
        scheduler.create_schedule(job_id=job1.id, cron_expression="0 2 * * *", is_active=True)
        scheduler.create_schedule(job_id=job2.id, cron_expression="0 4 * * *", is_active=False)
        db_session.commit()

        active = TranslationScheduler.list_active_schedules(db_session)
        assert len(active) == 1
        assert active[0].job_id == job1.id
    # #endregion test_list_active_schedules

    # #region test_get_next_executions_static [C:2] [TYPE Function]
    def test_get_next_executions_static(self):
        executions = TranslationScheduler.get_next_executions(
            cron_expression="0 2 * * *",
            timezone_str="UTC",
            n=3,
        )
        assert len(executions) == 3
        for dt_str in executions:
            assert "T02:00:00" in dt_str
    # #endregion test_get_next_executions_static

    # #region test_get_next_executions_invalid_cron [C:2] [TYPE Function]
    def test_get_next_executions_invalid_cron(self):
        executions = TranslationScheduler.get_next_executions(
            cron_expression="invalid-cron",
            timezone_str="UTC",
            n=3,
        )
        assert executions == []
    # #endregion test_get_next_executions_invalid_cron

    # #region test_get_next_executions_different_timezone [C:2] [TYPE Function]
    def test_get_next_executions_different_timezone(self):
        executions = TranslationScheduler.get_next_executions(
            cron_expression="0 2 * * *",
            timezone_str="Asia/Tokyo",
            n=2,
        )
        assert len(executions) == 2
    # #endregion test_get_next_executions_different_timezone
# #endregion TestScheduleCRUD
# #endregion TestTranslateSchedulesIntegration
