"""Tests API endpoints webhooks."""

from datetime import datetime
from unittest.mock import MagicMock, patch

import pytest
from fastapi import HTTPException
from sqlalchemy.exc import IntegrityError, SQLAlchemyError

from pricewatch.app.api.main import (
    list_webhooks,
    create_webhook,
    update_webhook,
    delete_webhook,
)
from pricewatch.app.api.schemas import WebhookCreate, WebhookUpdate


class MockWebhook:
    """Mock Webhook model."""
    def __init__(self, **kwargs):
        self.id = kwargs.get("id", 1)
        self.url = kwargs.get("url", "https://example.com/webhook")
        self.events = kwargs.get("events", ["price_change", "stock_change"])
        self.active = kwargs.get("active", True)
        self.created_at = kwargs.get("created_at", datetime.now())
        self.last_triggered_at = kwargs.get("last_triggered_at")


class TestListWebhooks:
    """Tests list_webhooks endpoint."""

    def test_list_webhooks_empty(self):
        """Liste vide de webhooks."""
        session = MagicMock()
        mock_query = MagicMock()
        mock_query.all.return_value = []
        session.query.return_value = mock_query

        with patch("pricewatch.app.api.main._webhook_to_out") as mock_to_out:
            result = list_webhooks(session=session)
            assert result == []


class TestCreateWebhook:
    """Tests create_webhook endpoint."""

    def test_create_webhook_integrity_error(self):
        """Erreur d'integrite lors de creation webhook leve 500."""
        # Note: le code actuel ne distingue pas IntegrityError de SQLAlchemyError
        session = MagicMock()
        session.add = MagicMock()
        session.commit = MagicMock(side_effect=IntegrityError("duplicate", {}, None))
        session.rollback = MagicMock()

        payload = WebhookCreate(
            event="price_change",
            url="https://example.com/webhook",
        )

        with patch("pricewatch.app.api.main.Webhook"):
            with pytest.raises(HTTPException) as exc_info:
                create_webhook(payload, session)
            assert exc_info.value.status_code == 500

    def test_create_webhook_db_error(self):
        """Erreur DB lors de creation webhook leve 500."""
        session = MagicMock()
        session.add = MagicMock()
        session.commit = MagicMock(side_effect=SQLAlchemyError("error"))
        session.rollback = MagicMock()

        payload = WebhookCreate(
            event="price_change",
            url="https://example.com/webhook",
        )

        with patch("pricewatch.app.api.main.Webhook"):
            with pytest.raises(HTTPException) as exc_info:
                create_webhook(payload, session)
            assert exc_info.value.status_code == 500


class TestUpdateWebhook:
    """Tests update_webhook endpoint."""

    def test_update_webhook_not_found(self):
        """Update webhook non trouve leve 404."""
        session = MagicMock()
        mock_query = MagicMock()
        mock_query.filter.return_value.one_or_none.return_value = None
        session.query.return_value = mock_query

        payload = WebhookUpdate(active=False)

        with pytest.raises(HTTPException) as exc_info:
            update_webhook(99999, payload, session)
        assert exc_info.value.status_code == 404

    def test_update_webhook_db_error(self):
        """Erreur DB lors d'update webhook leve 500."""
        session = MagicMock()
        mock_webhook = MockWebhook()
        mock_query = MagicMock()
        mock_query.filter.return_value.one_or_none.return_value = mock_webhook
        session.query.return_value = mock_query
        session.commit = MagicMock(side_effect=SQLAlchemyError("error"))
        session.rollback = MagicMock()

        payload = WebhookUpdate(active=False)

        with patch("pricewatch.app.api.main._webhook_to_out"):
            with pytest.raises(HTTPException) as exc_info:
                update_webhook(1, payload, session)
            assert exc_info.value.status_code == 500


class TestDeleteWebhook:
    """Tests delete_webhook endpoint."""

    def test_delete_webhook_not_found(self):
        """Delete webhook non trouve leve 404."""
        session = MagicMock()
        mock_query = MagicMock()
        mock_query.filter.return_value.one_or_none.return_value = None
        session.query.return_value = mock_query

        with pytest.raises(HTTPException) as exc_info:
            delete_webhook(99999, session)
        assert exc_info.value.status_code == 404

    def test_delete_webhook_success(self):
        """Delete webhook avec succes."""
        session = MagicMock()
        mock_webhook = MockWebhook()
        mock_query = MagicMock()
        mock_query.filter.return_value.one_or_none.return_value = mock_webhook
        session.query.return_value = mock_query
        session.delete = MagicMock()
        session.commit = MagicMock()

        result = delete_webhook(1, session)
        assert result == {"status": "deleted"}
        session.delete.assert_called_once()

    def test_delete_webhook_db_error(self):
        """Erreur DB lors de delete webhook leve 500."""
        session = MagicMock()
        mock_webhook = MockWebhook()
        mock_query = MagicMock()
        mock_query.filter.return_value.one_or_none.return_value = mock_webhook
        session.query.return_value = mock_query
        session.delete = MagicMock()
        session.commit = MagicMock(side_effect=SQLAlchemyError("error"))
        session.rollback = MagicMock()

        with pytest.raises(HTTPException) as exc_info:
            delete_webhook(1, session)
        assert exc_info.value.status_code == 500
