# scraper2_hj3415/app/dart/usecases/collect_dart_reports.py
from __future__ import annotations

import asyncio

from scraper2_hj3415.app.dart.adapters.out.mappers.dart_report_mapper import (
    DartReportMapper,
)
from scraper2_hj3415.app.dart.domain.dart_query import DartQuery
from scraper2_hj3415.app.dart.domain.entities.dart_report import DartReport
from scraper2_hj3415.app.dart.domain.services.dart_report_filter import DartReportFilter
from scraper2_hj3415.app.dart.domain.services.dart_title_normalizer import (
    DartTitleNormalizer,
)

from scraper2_hj3415.app.dart.dto.collect_dart_reports_result import (
    CollectDartReportsResult,
)
from scraper2_hj3415.app.dart.ports.dart.dart_client_port import DartClientPort
from scraper2_hj3415.app.dart.ports.universe.stock_universe_port import (
    StockUniversePort,
)


class CollectDartReportsUsecase:
    """
    OpenDART list.json 전체 페이지를 수집하고,
    도메인 정책에 따라 후처리한 공시 목록을 반환한다.
    """

    _dart_client: DartClientPort
    _stock_universe_port: StockUniversePort

    def __init__(
        self,
        dart_client: DartClientPort,
        stock_universe_port: StockUniversePort,
    ) -> None:
        self._dart_client = dart_client
        self._stock_universe_port = stock_universe_port

    async def execute(
        self,
        *,
        sdate: str | None = None,
        edate: str | None = None,
        corp_code: str | None = None,
        restrict_to_krx300: bool = True,
        only_kospi_kosdaq: bool = True,
        sleep_sec_between_pages: float = 0.0,
    ) -> CollectDartReportsResult:
        query = DartQuery(
            sdate=sdate,
            edate=edate,
            corp_code=corp_code,
        )

        first_page = await self._dart_client.list_reports(
            sdate=query.sdate,
            edate=query.edate,
            corp_code=query.corp_code,
            page_no=1,
        )

        page_dtos = [first_page]

        for page_no in range(2, first_page.total_page + 1):
            if sleep_sec_between_pages > 0:
                await asyncio.sleep(sleep_sec_between_pages)

            page_dto = await self._dart_client.list_reports(
                sdate=query.sdate,
                edate=query.edate,
                corp_code=query.corp_code,
                page_no=page_no,
            )
            page_dtos.append(page_dto)

        reports: list[DartReport] = [
            DartReportMapper.from_item_dto(item)
            for page in page_dtos
            for item in page.items
        ]

        raw_count = len(reports)

        reports = DartTitleNormalizer.normalize_whitespace(reports)

        if only_kospi_kosdaq:
            reports = DartReportFilter.only_kospi_kosdaq(reports)

        if restrict_to_krx300:
            stock_codes = set(await self._stock_universe_port.get_codes())
            reports = DartReportFilter.only_in_stock_codes(reports, stock_codes)

        reports = DartReportFilter.exclude_useless_titles(reports)

        return CollectDartReportsResult(
            total_pages=first_page.total_page,
            raw_count=raw_count,
            filtered_count=len(reports),
            reports=reports,
        )
