# tests/models/syndarix/test_project.py
"""
Unit tests for the Project model.
"""

import uuid
from datetime import datetime

import pytest
from sqlalchemy.exc import IntegrityError

from app.models.syndarix import (
    AutonomyLevel,
    Project,
    ProjectStatus,
)


class TestProjectModel:
    """Tests for Project model creation and fields."""

    def test_create_project_with_required_fields(self, db_session):
        """Test creating a project with only required fields."""
        project = Project(
            id=uuid.uuid4(),
            name="Test Project",
            slug="test-project",
        )
        db_session.add(project)
        db_session.commit()

        retrieved = db_session.query(Project).filter_by(slug="test-project").first()

        assert retrieved is not None
        assert retrieved.name == "Test Project"
        assert retrieved.slug == "test-project"
        assert retrieved.autonomy_level == AutonomyLevel.MILESTONE  # Default
        assert retrieved.status == ProjectStatus.ACTIVE  # Default
        assert retrieved.settings == {}  # Default empty dict
        assert retrieved.description is None
        assert retrieved.owner_id is None

    def test_create_project_with_all_fields(self, db_session):
        """Test creating a project with all optional fields."""
        project_id = uuid.uuid4()
        owner_id = uuid.uuid4()

        project = Project(
            id=project_id,
            name="Full Project",
            slug="full-project",
            description="A complete project with all fields",
            autonomy_level=AutonomyLevel.AUTONOMOUS,
            status=ProjectStatus.PAUSED,
            settings={"webhook_url": "https://example.com/webhook"},
            owner_id=owner_id,
        )
        db_session.add(project)
        db_session.commit()

        retrieved = db_session.query(Project).filter_by(id=project_id).first()

        assert retrieved.name == "Full Project"
        assert retrieved.slug == "full-project"
        assert retrieved.description == "A complete project with all fields"
        assert retrieved.autonomy_level == AutonomyLevel.AUTONOMOUS
        assert retrieved.status == ProjectStatus.PAUSED
        assert retrieved.settings == {"webhook_url": "https://example.com/webhook"}
        assert retrieved.owner_id == owner_id

    def test_project_unique_slug_constraint(self, db_session):
        """Test that projects cannot have duplicate slugs."""
        project1 = Project(
            id=uuid.uuid4(),
            name="Project One",
            slug="duplicate-slug",
        )
        db_session.add(project1)
        db_session.commit()

        project2 = Project(
            id=uuid.uuid4(),
            name="Project Two",
            slug="duplicate-slug",  # Same slug
        )
        db_session.add(project2)

        with pytest.raises(IntegrityError):
            db_session.commit()

        db_session.rollback()

    def test_project_timestamps(self, db_session):
        """Test that timestamps are automatically set."""
        project = Project(
            id=uuid.uuid4(),
            name="Timestamp Project",
            slug="timestamp-project",
        )
        db_session.add(project)
        db_session.commit()

        retrieved = db_session.query(Project).filter_by(slug="timestamp-project").first()

        assert isinstance(retrieved.created_at, datetime)
        assert isinstance(retrieved.updated_at, datetime)

    def test_project_update(self, db_session):
        """Test updating project fields."""
        project = Project(
            id=uuid.uuid4(),
            name="Original Name",
            slug="original-slug",
            status=ProjectStatus.ACTIVE,
        )
        db_session.add(project)
        db_session.commit()

        original_created_at = project.created_at

        # Update fields
        project.name = "Updated Name"
        project.status = ProjectStatus.COMPLETED
        project.settings = {"new_setting": "value"}
        db_session.commit()

        retrieved = db_session.query(Project).filter_by(slug="original-slug").first()

        assert retrieved.name == "Updated Name"
        assert retrieved.status == ProjectStatus.COMPLETED
        assert retrieved.settings == {"new_setting": "value"}
        assert retrieved.created_at == original_created_at
        assert retrieved.updated_at > original_created_at

    def test_project_delete(self, db_session):
        """Test deleting a project."""
        project_id = uuid.uuid4()
        project = Project(
            id=project_id,
            name="Delete Me",
            slug="delete-me",
        )
        db_session.add(project)
        db_session.commit()

        db_session.delete(project)
        db_session.commit()

        deleted = db_session.query(Project).filter_by(id=project_id).first()
        assert deleted is None

    def test_project_string_representation(self, db_session):
        """Test the string representation of a project."""
        project = Project(
            id=uuid.uuid4(),
            name="Repr Project",
            slug="repr-project",
            status=ProjectStatus.ACTIVE,
        )

        assert str(project) == "<Project Repr Project (repr-project) status=active>"
        assert repr(project) == "<Project Repr Project (repr-project) status=active>"


class TestProjectEnums:
    """Tests for Project enum fields."""

    def test_all_autonomy_levels(self, db_session):
        """Test that all autonomy levels can be stored."""
        for level in AutonomyLevel:
            project = Project(
                id=uuid.uuid4(),
                name=f"Project {level.value}",
                slug=f"project-{level.value}",
                autonomy_level=level,
            )
            db_session.add(project)
            db_session.commit()

            retrieved = db_session.query(Project).filter_by(slug=f"project-{level.value}").first()
            assert retrieved.autonomy_level == level

    def test_all_project_statuses(self, db_session):
        """Test that all project statuses can be stored."""
        for status in ProjectStatus:
            project = Project(
                id=uuid.uuid4(),
                name=f"Project {status.value}",
                slug=f"project-status-{status.value}",
                status=status,
            )
            db_session.add(project)
            db_session.commit()

            retrieved = db_session.query(Project).filter_by(slug=f"project-status-{status.value}").first()
            assert retrieved.status == status


class TestProjectSettings:
    """Tests for Project JSON settings field."""

    def test_complex_json_settings(self, db_session):
        """Test storing complex JSON in settings."""
        complex_settings = {
            "mcp_servers": ["gitea", "slack", "file-system"],
            "webhook_urls": {
                "on_issue_created": "https://example.com/issue",
                "on_sprint_completed": "https://example.com/sprint",
            },
            "notification_settings": {
                "email": True,
                "slack_channel": "#syndarix-updates",
            },
            "tags": ["important", "client-a"],
        }

        project = Project(
            id=uuid.uuid4(),
            name="Complex Settings Project",
            slug="complex-settings",
            settings=complex_settings,
        )
        db_session.add(project)
        db_session.commit()

        retrieved = db_session.query(Project).filter_by(slug="complex-settings").first()

        assert retrieved.settings == complex_settings
        assert retrieved.settings["mcp_servers"] == ["gitea", "slack", "file-system"]
        assert retrieved.settings["webhook_urls"]["on_issue_created"] == "https://example.com/issue"
        assert "important" in retrieved.settings["tags"]

    def test_empty_settings(self, db_session):
        """Test that empty settings defaults correctly."""
        project = Project(
            id=uuid.uuid4(),
            name="Empty Settings",
            slug="empty-settings",
        )
        db_session.add(project)
        db_session.commit()

        retrieved = db_session.query(Project).filter_by(slug="empty-settings").first()
        assert retrieved.settings == {}

    def test_update_settings(self, db_session):
        """Test updating settings field."""
        project = Project(
            id=uuid.uuid4(),
            name="Update Settings",
            slug="update-settings",
            settings={"initial": "value"},
        )
        db_session.add(project)
        db_session.commit()

        # Update settings
        project.settings = {"updated": "new_value", "additional": "data"}
        db_session.commit()

        retrieved = db_session.query(Project).filter_by(slug="update-settings").first()
        assert retrieved.settings == {"updated": "new_value", "additional": "data"}
