import json
from datetime import datetime

import pytest
from fastapi import status
from httpx import AsyncClient

from app.auth.services import create_access_token
from app.main import api_router
from tests.app.store.factories import SegmentFactory
from tests.app.user.factories import UserFactory


@pytest.mark.asyncio
@pytest.mark.parametrize("is_admin", [False, True])
@pytest.mark.parametrize("email_verified_at", [None, datetime.now()])
async def test_store_view_should_create_segment(
    client: AsyncClient, is_admin, email_verified_at
):
    """Test store view should create segment only by admin."""
    user = await UserFactory.create(
        is_admin=is_admin, email_verified_at=email_verified_at
    )
    token = await create_access_token(user=user)

    build = await SegmentFactory.build()
    data = {
        "title": build.title,
        "is_active": build.is_active,
        "image": build.image,
        "color": build.color,
    }

    response = await client.post(
        api_router.url_path_for("create_segment"),
        json=data,
        headers={"Authorization": f"Bearer {token['access_token']}"},
    )

    if is_admin and email_verified_at is not None:
        assert response.status_code == status.HTTP_201_CREATED
    else:
        assert response.status_code == status.HTTP_403_FORBIDDEN


@pytest.mark.asyncio
async def test_store_view_not_should_create_duplicate_segment(
    client: AsyncClient,
):
    """Test store view not should create duplicate segment."""
    user = await UserFactory.create(is_admin=True)
    token = await create_access_token(user=user)

    segment = await SegmentFactory.create()
    data = {
        "title": segment.title,
        "is_active": segment.is_active,
        "image": segment.image,
        "color": segment.color,
    }

    response = await client.post(
        api_router.url_path_for("create_segment"),
        json=data,
        headers={"Authorization": f"Bearer {token['access_token']}"},
    )

    assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY


@pytest.mark.asyncio
async def test_store_view_should_get_segments(client: AsyncClient):
    """Test store view should get segments."""
    segments = await SegmentFactory.create_batch(3)

    filter_spec = [
        {
            "field": "title",
            "op": "ilike",
            "value": "%segment title%",
        }
    ]
    sort_spec = [{"field": "id", "direction": "desc"}]

    response = await client.get(
        api_router.url_path_for("get_segments"),
        params={
            "filter": json.dumps(filter_spec),
            "sort": json.dumps(sort_spec),
        },
    )

    assert response.status_code == status.HTTP_200_OK
    assert response.json()["total"] == len(segments)


@pytest.mark.asyncio
@pytest.mark.parametrize("email_verified_at", [None, datetime.now()])
async def test_store_view_should_get_segment(
    client: AsyncClient, email_verified_at
):
    """Test store view should get segment."""
    user = await UserFactory.create(email_verified_at=email_verified_at)
    token = await create_access_token(user=user)

    segment = await SegmentFactory.create()

    response = await client.get(
        api_router.url_path_for("get_segment", segment_id=segment.id),
        headers={"Authorization": f"Bearer {token['access_token']}"},
    )

    if email_verified_at is not None:
        assert response.status_code == status.HTTP_200_OK
    else:
        assert response.status_code == status.HTTP_403_FORBIDDEN


@pytest.mark.asyncio
async def test_store_view_not_should_get_segment_not_found(
    client: AsyncClient,
):
    """Test store view not should get segment not found."""
    user = await UserFactory.create()
    token = await create_access_token(user=user)

    response = await client.get(
        api_router.url_path_for("get_segment", segment_id=10),
        headers={"Authorization": f"Bearer {token['access_token']}"},
    )

    assert response.status_code == status.HTTP_404_NOT_FOUND


@pytest.mark.asyncio
@pytest.mark.parametrize("is_admin", [True])
@pytest.mark.parametrize("email_verified_at", [datetime.now()])
async def test_store_view_should_update_segment(
    client: AsyncClient, is_admin, email_verified_at
):
    """Test store view should update segment only by admin."""
    user = await UserFactory.create(
        is_admin=is_admin, email_verified_at=email_verified_at
    )
    token = await create_access_token(user=user)

    segment = await SegmentFactory.create()
    build = await SegmentFactory.build()
    data = {
        "title": build.title,
        "is_active": build.is_active,
        "image": build.image,
        "color": build.color,
    }

    response = await client.put(
        api_router.url_path_for("update_segment", segment_id=segment.id),
        headers={"Authorization": f"Bearer {token['access_token']}"},
        json=data,
    )

    if is_admin and email_verified_at is not None:
        assert response.status_code == status.HTTP_200_OK
    else:
        assert response.status_code == status.HTTP_403_FORBIDDEN


@pytest.mark.asyncio
@pytest.mark.parametrize("is_admin", [True])
@pytest.mark.parametrize("email_verified_at", [datetime.now()])
async def test_store_view_should_delete_segment(
    client: AsyncClient, is_admin, email_verified_at
):
    """Test store view should delete segment only by admin."""
    user = await UserFactory.create(
        is_admin=is_admin, email_verified_at=email_verified_at
    )
    token = await create_access_token(user=user)

    segment = await SegmentFactory.create()

    response = await client.delete(
        api_router.url_path_for("delete_segment", segment_id=segment.id),
        headers={"Authorization": f"Bearer {token['access_token']}"},
    )

    if is_admin and email_verified_at is not None:
        assert response.status_code == status.HTTP_204_NO_CONTENT
    else:
        assert response.status_code == status.HTTP_403_FORBIDDEN

import json
from datetime import datetime

import pytest
from fastapi import status
from httpx import AsyncClient

from app.auth.services import create_access_token
from app.main import api_router
from tests.app.store.factories import SegmentFactory
from tests.app.user.factories import UserFactory


@pytest.mark.asyncio
@pytest.mark.parametrize("is_admin", [False, True])
@pytest.mark.parametrize("email_verified_at", [None, datetime.now()])
async def test_store_view_should_create_segment(
    client: AsyncClient, is_admin, email_verified_at
):
    """Test store view should create segment only by admin."""
    user = await UserFactory.create(
        is_admin=is_admin, email_verified_at=email_verified_at
    )
    token = await create_access_token(user=user)

    build = await SegmentFactory.build()
    data = {
        "title": build.title,
        "is_active": build.is_active,
        "image": build.image,
        "color": build.color,
    }

    response = await client.post(
        api_router.url_path_for("create_segment"),
        json=data,
        headers={"Authorization": f"Bearer {token['access_token']}"},
    )

    if is_admin and email_verified_at is not None:
        assert response.status_code == status.HTTP_201_CREATED
    else:
        assert response.status_code == status.HTTP_403_FORBIDDEN


@pytest.mark.asyncio
async def test_store_view_not_should_create_duplicate_segment(
    client: AsyncClient,
):
    """Test store view not should create duplicate segment."""
    user = await UserFactory.create(is_admin=True)
    token = await create_access_token(user=user)

    segment = await SegmentFactory.create()
    data = {
        "title": segment.title,
        "is_active": segment.is_active,
        "image": segment.image,
        "color": segment.color,
    }

    response = await client.post(
        api_router.url_path_for("create_segment"),
        json=data,
        headers={"Authorization": f"Bearer {token['access_token']}"},
    )

    assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY


@pytest.mark.asyncio
async def test_store_view_should_get_segments(client: AsyncClient):
    """Test store view should get segments."""
    segments = await SegmentFactory.create_batch(3)

    filter_spec = [
        {
            "field": "title",
            "op": "ilike",
            "value": "%segment title%",
        }
    ]
    sort_spec = [{"field": "id", "direction": "desc"}]

    response = await client.get(
        api_router.url_path_for("get_segments"),
        params={
            "filter": json.dumps(filter_spec),
            "sort": json.dumps(sort_spec),
        },
    )

    assert response.status_code == status.HTTP_200_OK
    assert response.json()["total"] == len(segments)


@pytest.mark.asyncio
@pytest.mark.parametrize("email_verified_at", [None, datetime.now()])
async def test_store_view_should_get_segment(
    client: AsyncClient, email_verified_at
):
    """Test store view should get segment."""
    user = await UserFactory.create(email_verified_at=email_verified_at)
    token = await create_access_token(user=user)

    segment = await SegmentFactory.create()

    response = await client.get(
        api_router.url_path_for("get_segment", segment_id=segment.id),
        headers={"Authorization": f"Bearer {token['access_token']}"},
    )

    if email_verified_at is not None:
        assert response.status_code == status.HTTP_200_OK
    else:
        assert response.status_code == status.HTTP_403_FORBIDDEN


@pytest.mark.asyncio
async def test_store_view_not_should_get_segment_not_found(
    client: AsyncClient,
):
    """Test store view not should get segment not found."""
    user = await UserFactory.create()
    token = await create_access_token(user=user)

    response = await client.get(
        api_router.url_path_for("get_segment", segment_id=10),
        headers={"Authorization": f"Bearer {token['access_token']}"},
    )

    assert response.status_code == status.HTTP_404_NOT_FOUND


@pytest.mark.asyncio
@pytest.mark.parametrize("is_admin", [True])
@pytest.mark.parametrize("email_verified_at", [datetime.now()])
async def test_store_view_should_update_segment(
    client: AsyncClient, is_admin, email_verified_at
):
    """Test store view should update segment only by admin."""
    user = await UserFactory.create(
        is_admin=is_admin, email_verified_at=email_verified_at
    )
    token = await create_access_token(user=user)

    segment = await SegmentFactory.create()
    build = await SegmentFactory.build()
    data = {
        "title": build.title,
        "is_active": build.is_active,
        "image": build.image,
        "color": build.color,
    }

    response = await client.put(
        api_router.url_path_for("update_segment", segment_id=segment.id),
        headers={"Authorization": f"Bearer {token['access_token']}"},
        json=data,
    )

    if is_admin and email_verified_at is not None:
        assert response.status_code == status.HTTP_200_OK
    else:
        assert response.status_code == status.HTTP_403_FORBIDDEN


@pytest.mark.asyncio
@pytest.mark.parametrize("is_admin", [True])
@pytest.mark.parametrize("email_verified_at", [datetime.now()])
async def test_store_view_should_delete_segment(
    client: AsyncClient, is_admin, email_verified_at
):
    """Test store view should delete segment only by admin."""
    user = await UserFactory.create(
        is_admin=is_admin, email_verified_at=email_verified_at
    )
    token = await create_access_token(user=user)

    segment = await SegmentFactory.create()

    response = await client.delete(
        api_router.url_path_for("delete_segment", segment_id=segment.id),
        headers={"Authorization": f"Bearer {token['access_token']}"},
    )

    if is_admin and email_verified_at is not None:
        assert response.status_code == status.HTTP_204_NO_CONTENT
    else:
        assert response.status_code == status.HTTP_403_FORBIDDEN

Test store view should create segment only by admin. Test store view not should create duplicate segment. Test store view should get segments. Test store view should get segment. Test store view not should get segment not found. Test store view should update segment only by admin. Test store view should delete segment only by admin.