from . import models
from loguru import logger
import logging
from curl_cffi.requests import AsyncSession
from parsel import Selector
from typing import List

logging.basicConfig(level=logging.DEBUG)


class Client:
    def __init__(
        self, user_agent: str | None = None, timeout: int = 10, proxy: str | None = None
    ):
        self.user_agent = user_agent
        self.timeout = timeout
        self.proxy = proxy

    @property
    def default_headers(self) -> dict:
        return {
            "Host": "hanime1.me",
            "User-Agent": self.user_agent
            or "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
        }

    def get_session(self) -> AsyncSession:
        s = AsyncSession(
            timeout=self.timeout, impersonate="chrome124", base_url="https://hanime1.me"
        )
        if self.proxy:
            s.proxies["all"] = self.proxy
        return s

    async def search(self, params: models.SearchParams) -> List[models.SearchItem]:
        async with self.get_session() as s:
            params_dict = params.model_dump()
            params_dict.update({"type": params.search_type})
            result = await s.get(
                "/search",
                params={key: value for key, value in params_dict.items() if value},
            )
            content = result.text
            result.raise_for_status()
            selector = Selector(text=content)
            content_el_text = selector.css("div.content-padding-new").get()
            if not content_el_text:
                return []
            content_el = Selector(text=content_el_text)
            elements = content_el.css("div.col-xs-12.search-doujin-videos").getall()
            data = []
            for element_text in elements:
                if not element_text:
                    continue
                element = Selector(text=element_text)
                link = element.css("a.overlay::attr(href)").get()
                if not link:
                    continue
                video_id = int(link.split("=")[1])
                title = element.css("div.card-mobile-title::text").get() or ""
                author_name = element.css("a.card-mobile-user::text").get() or ""
                all_imgs = element.css("img::attr(src)").getall()
                img_link = all_imgs[1] if len(all_imgs) > 1 else ""
                durations = element.css("div.card-mobile-duration::text").getall()
                viewings_str = durations[0].strip()
                time_duration_str = durations[1].strip()

                data.append(
                    models.SearchItem(
                        video_id=video_id,
                        title=title,
                        author_name=author_name,
                        img_link=img_link,
                        viewings_str=viewings_str,
                        time_duration_str=time_duration_str,
                    )
                )
            logger.debug(f"search result {data}")
            return data

    async def get_video(self, video_id: int) -> models.Video:
        async with self.get_session() as s:
            result = await s.get(f"/watch?v={video_id}")
            result.raise_for_status()
            content_selector = Selector(text=result.text)
            title = content_selector.css("h3#shareBtn-title::text").get() or ""
            desc = content_selector.css("div.video-caption-text::text").get() or ""
            author = content_selector.css("a#video-artist-name::text").get() or ""
            tag_divs = content_selector.css("div.single-video-tag").getall()

            tags = [Selector(text=div_el).css("a::text").get() for div_el in tag_divs]
            comic_href = (
                content_selector.xpath("//a[.//i[@id='video-comic-btn']]/@href").get()
                or ""
            )

            relate_videos_text = content_selector.css(
                "div.related-video-margin-bottom"
            ).getall()
            relate_vides: List[models.RelateVideo] = []
            for video_text in relate_videos_text:
                s = Selector(text=video_text)
                title = s.css("div.home-rows-videos-title::text").get() or ""
                img_link = s.css("img::attr(src)").get() or ""
                relate_vides.append(
                    models.RelateVideo(
                        title=title,
                        img_link=img_link,
                    )
                )

            result = models.Video(
                id=video_id,
                title=title.strip(),
                desc=desc.strip(),
                author=author.strip(),
                tags=[tag for tag in tags if tag],
                comic_id=int(comic_href.split("/")[-1]),
                relate_videos=relate_vides,
            )

            logger.debug(f"get video result {result}")
            return result

    async def get_video_downloads(self, video_id: int) -> List[models.DownloadItem]:
        async with self.get_session() as s:
            result = await s.get(f"/download?v={video_id}")
            result.raise_for_status()
            selector = Selector(text=result.text)
            rows = selector.xpath(
                "//table[@class='download-table']/tr[position()>1]"
            ).getall()
            downloads: List[models.DownloadItem] = []
            for row in rows:
                row_selector = Selector(text=row)
                quality = row_selector.xpath(".//td[2]//text()").get() or ""
                format_type = row_selector.xpath(".//td[3]/text()").get() or ""
                link = row_selector.xpath(".//td[5]/a/@href").get() or ""
                downloads.append(
                    models.DownloadItem(
                        quality=quality.strip(),
                        format=format_type.strip(),
                        link=link.strip(),
                    )
                )
            logger.debug(f"get downloads result {downloads}")
            return downloads

    async def get_comic(self, comic_id: int) -> models.Comic:
        async with self.get_session() as s:
            resp = await s.get(f"/comic/{comic_id}")
            resp.raise_for_status()
            tree = Selector(text=resp.text)
            title = " ".join(
                tree.xpath(
                    '//h3[@class="title comics-metadata-top-row"]/span/text()'
                ).getall()
            )
            desc = " ".join(
                tree.xpath(
                    "//h4[@class='title comics-metadata-margin-top']/span/text()"
                ).getall()
            )

            # 解析标签
            tags = tree.xpath('//h5[contains(text(),"標籤：")]/a/div/text()').getall()

            # 解析作者
            author = (
                tree.xpath('//h5[contains(text(),"作者：")]/a/div/text()').get() or ""
            )

            # 解析页数
            total_pages = (
                tree.xpath('//h5[contains(text(),"頁數：")]/div/text()').get() or ""
            )

            gallery_id = tree.xpath("//img[@data-srcset]").get() or ""
            # https://t2.nhentai.net/galleries/{gallery_id}/{page}t.jpg
            result = models.Comic(
                id=comic_id,
                title=title,
                desc=desc,
                tags=tags,
                author=author,
                total_pages=int(total_pages),
                gallery_id=int(gallery_id.split("/")[-2]),
            )
            logger.debug(f"get comic result {result}")
            return result


if __name__ == "__main__":
    import asyncio

    c = Client()
    asyncio.run(c.get_comic(98763))
