from typing import TYPE_CHECKING

import respx
import pytest
from httpx import Response
from nonebug.app import App
from nonebot.compat import type_validate_python

from .utils import get_json

if TYPE_CHECKING:
    from nonebot_bison.platform.ceobecanteen import CeobeCanteen


@pytest.fixture
def dummy_only_open_user_subinfo(app: App):
    from nonebot_plugin_saa import TargetQQGroup

    from nonebot_bison.types import UserSubInfo

    user = TargetQQGroup(group_id=123)
    return UserSubInfo(user=user, categories=[1], tags=[])


@pytest.fixture
def ceobecanteen(app: App):
    from nonebot_bison.utils import ProcessContext
    from nonebot_bison.platform import platform_manager
    from nonebot_bison.platform.ceobecanteen.platform import CeobeCanteenClientManager

    return platform_manager["ceobecanteen"](ProcessContext(CeobeCanteenClientManager()))


@pytest.fixture(scope="module")
def dummy_target() -> str:
    return "7d23708b-e424-418b-b4c4-43c370c3b6d0"


@pytest.fixture(scope="module")
def ceobecanteen_targets() -> dict:
    return get_json("ceobecanteen_targets.json")


@pytest.fixture(scope="module")
def ceobecanteen_comb_id_0() -> dict:
    return get_json("ceobecanteen_comb_id_0.json")


@pytest.fixture(scope="module")
def ceobecanteen_comb_id_1() -> dict:
    return get_json("ceobecanteen_comb_id_1.json")


@pytest.fixture(scope="module")
def ceobecanteen_cookie_id_0() -> dict:
    return get_json("ceobecanteen_cookie_id_0.json")


@pytest.fixture(scope="module")
def ceobecanteen_cookie_id_1() -> dict:
    return get_json("ceobecanteen_cookie_id_1.json")


@pytest.fixture(scope="module")
def ceobecanteen_cookies_0() -> dict:
    return get_json("ceobecanteen_cookies_0.json")


@pytest.fixture(scope="module")
def ceobecanteen_cookies_1() -> dict:
    return get_json("ceobecanteen_cookies_1.json")


@pytest.mark.asyncio()
async def test_parse_retweet(app: App):
    from nonebot_bison.platform.ceobecanteen.models import CookiesResponse

    cookie_with_retweet = type_validate_python(CookiesResponse, get_json("ceobecanteen_cookies_with_retweet.json"))
    assert cookie_with_retweet.data.cookies[0].item.retweeted


@pytest.mark.render()
async def test_ceobe_snapshot(app: App, ceobecanteen: "CeobeCanteen"):
    from nonebot_bison.platform.ceobecanteen.models import CeobeCookie

    sp_coolies = get_json("ceobe_special_cookies.json")

    # arknights-game:bulletin-list but not need to snapshot
    cookie_bulletin_type2 = type_validate_python(CeobeCookie, sp_coolies[0])
    assert cookie_bulletin_type2.source.type == "arknights-game:bulletin-list"
    post = await ceobecanteen.parse(cookie_bulletin_type2)
    assert post.images
    assert len(post.images) == 1
    assert post.content == "【联合行动】\n定向寻访开启"

    cookie_bulletin_type1 = type_validate_python(CeobeCookie, sp_coolies[1])
    post2 = await ceobecanteen.parse(cookie_bulletin_type1)
    assert post2.images
    assert len(post2.images) == 1
    assert not post2.content

    cookie_offical = type_validate_python(CeobeCookie, sp_coolies[2])
    post3 = await ceobecanteen.parse(cookie_offical)
    assert post3.images
    assert len(post3.images) == 1
    assert not post3.content

    cookie_common = type_validate_python(CeobeCookie, sp_coolies[3])
    post4 = await ceobecanteen.parse(cookie_common)
    assert post4.images
    assert len(post4.images) == 7
    assert post4.content


@pytest.mark.skip("极限测试, 不在CI中运行")
@pytest.mark.asyncio()
async def test_parse_crazy(app: App, ceobecanteen):
    from nonebot_plugin_saa import Image

    from nonebot_bison.platform.ceobecanteen import CeobeCanteen
    from nonebot_bison.platform.ceobecanteen.models import CeobeCookie

    def show(p: bytes):
        import io

        from PIL import Image

        Image.open(io.BytesIO(p)).show()

    def ext(m: Image):
        d = m.data["image"]
        assert isinstance(d, bytes)
        return d

    assert isinstance(ceobecanteen, CeobeCanteen)

    cookie_offical = type_validate_python(CeobeCookie, get_json("ceobe_looooong_bulletin.json"))
    post4 = await ceobecanteen.parse(cookie_offical)
    show(ext((await post4.generate_messages())[0][0]))  # type: ignore


@pytest.mark.asyncio()
@respx.mock
async def test_batch_fetch_new_with_single(
    app: App,
    dummy_target,
    dummy_only_open_user_subinfo,
    ceobecanteen: "CeobeCanteen",
    ceobecanteen_targets,
    ceobecanteen_comb_id_0,
    ceobecanteen_cookie_id_0,
    ceobecanteen_cookie_id_1,
    ceobecanteen_cookies_0,
    ceobecanteen_cookies_1,
):
    from nonebot_bison.post import Post
    from nonebot_bison.types import SubUnit

    mock_respone_headers = {
        "Content-Encoding": "br",
        "Content-Type": "application/json; charset=utf-8",
        "Date": "Thu, 08 Jul 2021 14:00:00 GMT",
        # "Date": datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT"),
        "Vary": "origin; access-control-request-method; access-control-request-headers",
    }

    targets_router = respx.get("https://server.ceobecanteen.top/api/v1/canteen/config/datasource/list")
    comb_id_router = respx.post("https://server.ceobecanteen.top/api/v1/canteen/user/getDatasourceComb")
    cookie_id_router = respx.get("http://cdn.ceobecanteen.top/datasource-comb/2")
    cookies_router = respx.get("https://server-cdn.ceobecanteen.top/api/v1/cdn/cookie/mainList/cookieList")

    targets_router.mock(return_value=Response(200, json=ceobecanteen_targets, headers=mock_respone_headers))
    comb_id_router.mock(return_value=Response(200, json=ceobecanteen_comb_id_0))
    cookie_id_router.mock(return_value=Response(200, json=ceobecanteen_cookie_id_0, headers=mock_respone_headers))
    cookies_router.mock(return_value=Response(200, json=ceobecanteen_cookies_0, headers=mock_respone_headers))

    assert await ceobecanteen.get_target_name(None, dummy_target) == "明日方舟-B站"
    assert await ceobecanteen.parse_target("明日方舟-B站") == dummy_target

    res1 = await ceobecanteen.batch_fetch_new_post([SubUnit(dummy_target, [dummy_only_open_user_subinfo])])
    assert comb_id_router.called
    assert cookie_id_router.called
    assert cookies_router.called
    assert res1 == []

    res2 = await ceobecanteen.batch_fetch_new_post([SubUnit(dummy_target, [dummy_only_open_user_subinfo])])
    assert comb_id_router.call_count == 1
    assert cookie_id_router.call_count == 2
    assert cookies_router.call_count == 1
    assert res2 == []

    cookie_id_router.mock(return_value=Response(200, json=ceobecanteen_cookie_id_1))
    cookies_router.mock(return_value=Response(200, json=ceobecanteen_cookies_1))
    res3 = await ceobecanteen.batch_fetch_new_post([SubUnit(dummy_target, [dummy_only_open_user_subinfo])])
    assert comb_id_router.call_count == 1
    assert cookie_id_router.call_count == 3
    assert cookies_router.call_count == 2

    post3: Post = res3[0][1][0]
    assert not post3.title
    assert (
        post3.content
        == "【新增服饰】\n//正午余光 - 苦艾\nEPOQUE子品牌 [昔时/Passe]系列精选款/正午余光。苦艾曾经的校服。"
        "在乌萨斯,学生穿校服出操,就像是跟在一把犁后面一行整齐的秧苗。\n\n_____________\n只可惜,"
        "阳光能照在这把犁上的时间总是太短了。但这样的事,那个春天之前的她还不明白。"
    )
    assert post3.images
    assert len(post3.images) == 2
    assert post3.timestamp
    assert post3.url
    assert post3.avatar
    assert post3.nickname == "明日方舟-B站"
    assert post3.description
    assert post3.platform.platform_name == "ceobecanteen"

    image1_router = respx.get("https://i0.hdslb.com/bfs/new_dyn/62e053ba7efc18f15bfd195e2d2de984161775300.jpg")
    image2_router = respx.get("https://i0.hdslb.com/bfs/new_dyn/590a69665209ac220ea8a57f749d5267161775300.gif")
    image1_router.mock(return_value=Response(200, content=b"image1"))
    image2_router.mock(return_value=Response(200, content=b"image2"))
    await post3.generate_messages()


@pytest.mark.asyncio()
@respx.mock
async def test_parse_target_fuzzy(app: App, ceobecanteen: "CeobeCanteen", dummy_target, ceobecanteen_targets):
    from nonebot_bison.platform.ceobecanteen import CeobeCanteen

    mock_respone_headers = {
        "Content-Encoding": "br",
        "Content-Type": "application/json; charset=utf-8",
        "Date": "Thu, 08 Jul 2021 14:00:00 GMT",
        # "Date": datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT"),
        "Vary": "origin; access-control-request-method; access-control-request-headers",
    }

    targets_router = respx.get("https://server.ceobecanteen.top/api/v1/canteen/config/datasource/list")
    targets_router.mock(return_value=Response(200, json=ceobecanteen_targets, headers=mock_respone_headers))

    # check load data ok
    assert await ceobecanteen.get_target_name(None, dummy_target) == "明日方舟-B站"
    assert await ceobecanteen.parse_target("明日方舟-B站") == dummy_target

    # check fuzzy search
    # try:
    #     assert await ceobecanteen.parse_target("丸子姐") == dummy_target
    # except CeobeCanteen.ParseTargetException as e:
    #     logger.error(e.prompt)
    #     pytest.fail("fuzzy search failed")
    with pytest.raises(CeobeCanteen.ParseTargetException) as pe1:
        await ceobecanteen.parse_target("丸子姐")

    assert pe1.value.prompt
    assert "Wan顽子-B站\nWan顽子-微博" in pe1.value.prompt

    with pytest.raises(CeobeCanteen.ParseTargetException) as pe2:
        await ceobecanteen.parse_target("明日方舟")

    assert pe2.value.prompt
    assert "明日方舟-B站" in pe2.value.prompt