import uuid
from datetime import datetime

import pytest
from sqlalchemy import select

from app.models.lifecycle import LifecycleProject, ProjectStage
from app.models.organization import Organization
from app.models.user import User


class TestLifecycleProjectModel:

    def test_lifecycle_project_table_name(self):
        assert LifecycleProject.__tablename__ == "lifecycle_projects"

    def test_project_stage_table_name(self):
        assert ProjectStage.__tablename__ == "project_stages"

    def test_lifecycle_project_has_required_fields(self):
        fields = LifecycleProject.__table__.columns.keys()
        assert "id" in fields
        assert "organization_id" in fields
        assert "brand_name" in fields
        assert "brand_aliases" in fields
        assert "current_stage" in fields
        assert "status" in fields
        assert "created_by" in fields
        assert "created_at" in fields
        assert "updated_at" in fields

    def test_project_stage_has_required_fields(self):
        fields = ProjectStage.__table__.columns.keys()
        assert "id" in fields
        assert "project_id" in fields
        assert "stage_number" in fields
        assert "status" in fields
        assert "started_at" in fields
        assert "completed_at" in fields
        assert "notes" in fields
        assert "metrics" in fields

    def test_lifecycle_project_field_types(self):
        columns = LifecycleProject.__table__.columns
        id_type = str(columns["id"].type).upper()
        assert "UUID" in id_type or "CHAR" in id_type
        org_id_type = str(columns["organization_id"].type).upper()
        assert "UUID" in org_id_type or "CHAR" in org_id_type
        brand_name_type = str(columns["brand_name"].type).upper()
        assert "VARCHAR" in brand_name_type or "STRING" in brand_name_type
        assert "INTEGER" in str(columns["current_stage"].type).upper()
        status_type = str(columns["status"].type).upper()
        assert "VARCHAR" in status_type or "STRING" in status_type

    def test_project_stage_field_types(self):
        columns = ProjectStage.__table__.columns
        id_type = str(columns["id"].type).upper()
        assert "UUID" in id_type or "CHAR" in id_type
        project_id_type = str(columns["project_id"].type).upper()
        assert "UUID" in project_id_type or "CHAR" in project_id_type
        assert "INTEGER" in str(columns["stage_number"].type).upper()
        status_type = str(columns["status"].type).upper()
        assert "VARCHAR" in status_type or "STRING" in status_type

    def test_lifecycle_project_relationships_defined(self):
        relationships = LifecycleProject.__mapper__.relationships
        rel_keys = relationships.keys()
        assert "stages" in rel_keys
        assert "organization" in rel_keys
        assert "creator" in rel_keys

    def test_project_stage_relationships_defined(self):
        relationships = ProjectStage.__mapper__.relationships
        rel_keys = relationships.keys()
        assert "project" in rel_keys

    def test_lifecycle_project_default_stage(self):
        columns = LifecycleProject.__table__.columns
        stage_col = columns["current_stage"]
        assert stage_col.server_default is not None

    def test_lifecycle_project_default_status(self):
        columns = LifecycleProject.__table__.columns
        status_col = columns["status"]
        assert status_col.server_default is not None

    def test_project_stage_default_status(self):
        columns = ProjectStage.__table__.columns
        status_col = columns["status"]
        assert status_col.server_default is not None

    @pytest.mark.asyncio
    async def test_lifecycle_project_create(self, async_session, test_user):
        org = Organization(
            name="Lifecycle Test Org",
            slug="lifecycle-test-org",
        )
        async_session.add(org)
        await async_session.commit()
        await async_session.refresh(org)

        project = LifecycleProject(
            id=uuid.uuid4(),
            organization_id=org.id,
            brand_name="Test Brand",
            brand_aliases=["TB", "TestBrand"],
            current_stage=1,
            status="active",
            created_by=test_user.id,
        )
        async_session.add(project)
        await async_session.commit()
        await async_session.refresh(project)

        assert project.id is not None
        assert project.organization_id == org.id
        assert project.brand_name == "Test Brand"
        assert project.brand_aliases == ["TB", "TestBrand"]
        assert project.current_stage == 1
        assert project.status == "active"
        assert project.created_by == test_user.id
        assert project.created_at is not None
        assert project.updated_at is not None

    @pytest.mark.asyncio
    async def test_lifecycle_project_default_values(self, async_session, test_user):
        org = Organization(
            name="Default Lifecycle Org",
            slug="default-lifecycle-org",
        )
        async_session.add(org)
        await async_session.commit()
        await async_session.refresh(org)

        project = LifecycleProject(
            organization_id=org.id,
            brand_name="Default Brand",
            created_by=test_user.id,
        )
        async_session.add(project)
        await async_session.commit()
        await async_session.refresh(project)

        assert project.brand_aliases == []
        assert project.current_stage == 1
        assert project.status == "active"

    @pytest.mark.asyncio
    async def test_project_stage_create(self, async_session, test_user):
        org = Organization(
            name="Stage Test Org",
            slug="stage-test-org",
        )
        async_session.add(org)
        await async_session.commit()
        await async_session.refresh(org)

        project = LifecycleProject(
            organization_id=org.id,
            brand_name="Stage Test Brand",
            created_by=test_user.id,
        )
        async_session.add(project)
        await async_session.commit()
        await async_session.refresh(project)

        stage = ProjectStage(
            id=uuid.uuid4(),
            project_id=project.id,
            stage_number=1,
            status="in_progress",
            notes="Starting brand awareness phase",
            metrics={"awareness_score": 45},
        )
        async_session.add(stage)
        await async_session.commit()
        await async_session.refresh(stage)

        assert stage.id is not None
        assert stage.project_id == project.id
        assert stage.stage_number == 1
        assert stage.status == "in_progress"
        assert stage.notes == "Starting brand awareness phase"
        assert stage.metrics == {"awareness_score": 45}
        assert stage.started_at is None
        assert stage.completed_at is None

    @pytest.mark.asyncio
    async def test_project_stage_default_values(self, async_session, test_user):
        org = Organization(
            name="Default Stage Org",
            slug="default-stage-org",
        )
        async_session.add(org)
        await async_session.commit()
        await async_session.refresh(org)

        project = LifecycleProject(
            organization_id=org.id,
            brand_name="Default Stage Brand",
            created_by=test_user.id,
        )
        async_session.add(project)
        await async_session.commit()
        await async_session.refresh(project)

        stage = ProjectStage(
            project_id=project.id,
            stage_number=2,
        )
        async_session.add(stage)
        await async_session.commit()
        await async_session.refresh(stage)

        assert stage.status == "pending"
        assert stage.notes is None
        assert stage.metrics is None
