import uuid
from unittest.mock import AsyncMock, patch

import pytest

from tests.fixtures.auth import _make_user, _to_uuid


class TestMonetizationFlow:
    @pytest.mark.asyncio
    async def test_full_monetization_flow(self, async_client, async_session):
        user = _make_user(email="monetization@example.com", plan="free")
        async_session.add(user)
        await async_session.commit()
        await async_session.refresh(user)

        from app.api.deps import get_current_user, get_db
        from app.main import app

        async def override_get_db():
            yield async_session

        async def override_get_current_user():
            return user

        app.dependency_overrides[get_db] = override_get_db
        app.dependency_overrides[get_current_user] = override_get_current_user

        try:
            brand_resp = await async_client.post(
                "/api/v1/onboarding/brand",
                json={"name": "MonoBrand", "industry": "technology"},
            )
            assert brand_resp.status_code == 201
            brand_data = brand_resp.json()
            brand_id = brand_data["id"]
            assert brand_data["name"] == "MonoBrand"

            onboarding_resp = await async_client.post(
                f"/api/v1/onboarding/complete/{brand_id}"
            )
            assert onboarding_resp.status_code == 200
            assert onboarding_resp.json()["success"] is True

            with patch("app.api.onboarding.DataCollectorService") as mock_collector_cls:
                mock_collector = AsyncMock()
                mock_collector_cls.return_value = mock_collector

                from app.services.diagnosis.data_collector import DataCollectionResult
                from app.services.diagnosis.geo_diagnosis import GEODiagnosisInput, GEODiagnosisService

                input_data = GEODiagnosisInput(
                    has_direct_answer=True,
                    has_brand_definition=True,
                    has_author_bio=True,
                    author_credentials_complete=0.8,
                    has_organization=True,
                    content_depth_score=0.7,
                    answer_ownership_rate=0.3,
                )
                mock_collector.collect.return_value = DataCollectionResult(
                    diagnosis_input=input_data,
                )

                service = GEODiagnosisService()
                result = service.diagnose(input_data)

                with patch("app.api.onboarding.GEODiagnosisService", return_value=service):
                    health_resp = await async_client.get(
                        f"/api/v1/onboarding/health-report/{brand_id}"
                    )

            assert health_resp.status_code == 200
            health_data = health_resp.json()
            assert health_data["brand_id"] == brand_id
            assert "overall_score" in health_data
            assert "dimensions" in health_data
            assert health_data["is_full_report"] is False

            order_resp = await async_client.post(
                "/api/v1/payments/orders",
                json={"plan": "pro", "payment_provider": "wechat"},
            )
            assert order_resp.status_code == 201
            order_data = order_resp.json()
            order_id = order_data["order_id"]
            assert "pay_url" in order_data
            assert order_data["amount"] == 599
            assert order_data["status"] == "pending"

            from app.models.payment_order import PaymentOrder as PaymentOrderModel
            from app.services.payment.base import PaymentCallback

            from sqlalchemy import select
            stmt = select(PaymentOrderModel).where(
                PaymentOrderModel.id == uuid.UUID(order_id)
            )
            db_result = await async_session.execute(stmt)
            order = db_result.scalar_one()

            callback = PaymentCallback(
                order_id=str(order.id),
                payment_id=f"wx_pay_{order.id}",
                amount=599,
                status="success",
                raw_data={"out_trade_no": str(order.id), "result_code": "SUCCESS"},
            )

            from app.api.payments import _process_callback
            await _process_callback(async_session, callback, "wechat")
            await async_session.commit()

            await async_session.refresh(order)
            assert order.status == "paid"
            assert order.payment_id is not None

            await async_session.refresh(user)
            assert user.plan == "pro"
            assert user.max_queries == 50

            with patch("app.api.onboarding.DataCollectorService") as mock_collector_cls:
                mock_collector = AsyncMock()
                mock_collector_cls.return_value = mock_collector

                from app.services.diagnosis.data_collector import DataCollectionResult
                from app.services.diagnosis.geo_diagnosis import GEODiagnosisInput, GEODiagnosisService

                input_data = GEODiagnosisInput(
                    has_direct_answer=True,
                    has_brand_definition=True,
                    has_author_bio=True,
                    author_credentials_complete=0.8,
                    has_organization=True,
                    content_depth_score=0.7,
                    answer_ownership_rate=0.3,
                )
                mock_collector.collect.return_value = DataCollectionResult(
                    diagnosis_input=input_data,
                )

                service = GEODiagnosisService()
                result = service.diagnose(input_data)

                with patch("app.api.onboarding.GEODiagnosisService", return_value=service):
                    paid_health_resp = await async_client.get(
                        f"/api/v1/onboarding/health-report/{brand_id}"
                    )

            assert paid_health_resp.status_code == 200
            paid_health_data = paid_health_resp.json()
            assert paid_health_data["is_full_report"] is True
            assert len(paid_health_data["dimensions"]) == 6

            from app.models.diagnosis_record import DiagnosisRecord

            diag_record = DiagnosisRecord(
                brand_id=uuid.UUID(brand_id),
                user_id=_to_uuid(user.id),
                diagnosis_type="geo",
                status="completed",
                overall_score=result.overall_score,
                result_json=result.to_dict(),
            )
            async_session.add(diag_record)
            await async_session.commit()
            await async_session.refresh(diag_record)

            attr_resp = await async_client.post(
                "/api/v1/attribution/start",
                json={"brand_id": brand_id},
            )
            assert attr_resp.status_code == 200
            attr_data = attr_resp.json()
            assert "id" in attr_data
            assert attr_data["brand_id"] == brand_id
            assert attr_data["baseline_score"] == result.overall_score
            assert attr_data["status"] == "tracking"

            roi_resp = await async_client.get(
                f"/api/v1/attribution/roi/{brand_id}"
            )
            assert roi_resp.status_code == 200
            roi_data = roi_resp.json()
            assert "roi_percentage" in roi_data
            assert "value_generated" in roi_data
            assert "subscription_cost" in roi_data
            assert roi_data["brand_name"] == "MonoBrand"
            assert roi_data["current_plan"] == "pro"

        finally:
            app.dependency_overrides.clear()
