"""Automated test suite for Department of Construction (SXD) AIHawk Stealth Anti-Bot Crawler."""

from __future__ import annotations

import asyncio
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from fastapi.testclient import TestClient

from app.main import create_app
from app.modules.inventory.application.crawl_and_sync_sxd_prices_use_case import (
    CrawlAndSyncSxdPricesUseCase,
)
from app.modules.inventory.domain.ports.sxd_crawler_port import (
    ISxdCrawlerPort,
    SxdAnnouncement,
    SxdAttachmentInfo,
)
from app.modules.inventory.infrastructure.adapters.sxd_stealth_crawler_adapter import (
    AIHAWK_STEALTH_JS,
    DEFAULT_DESKTOP_UA,
    SxdStealthCrawlerAdapter,
)

client = TestClient(create_app())
AUTH_HEADERS = {"Authorization": "Bearer dev-test-token"}


def test_sxd_crawler_domain_port_and_adapter_contract():
    """Kiểm tra tuân thủ Kiến trúc Lục giác (Hexagonal Architecture) và Protocol Interface."""
    adapter = SxdStealthCrawlerAdapter()
    assert isinstance(adapter, ISxdCrawlerPort)
    assert hasattr(adapter, "crawl_latest_announcements")
    assert hasattr(adapter, "download_announcement_files")


def test_aihawk_stealth_anti_bot_configuration():
    """Kiểm tra cấu hình bypass chặn bot theo nguyên lý AIHawk."""
    # 1. Kiểm tra kịch bản JavaScript loại bỏ navigator.webdriver và giả lập window.chrome
    assert "navigator.webdriver" in AIHAWK_STEALTH_JS
    assert "window.chrome" in AIHAWK_STEALTH_JS
    assert "languages" in AIHAWK_STEALTH_JS
    assert "plugins" in AIHAWK_STEALTH_JS

    # 2. Kiểm tra User-Agent thực tế của Desktop Chrome
    assert "Windows NT 10.0" in DEFAULT_DESKTOP_UA
    assert "Chrome" in DEFAULT_DESKTOP_UA
    assert "Safari" in DEFAULT_DESKTOP_UA


def test_crawl_and_sync_sxd_prices_use_case_orchestration(tmp_path: Path):
    """Kiểm thử Use Case điều phối thu thập và đồng bộ thông báo giá SXD."""
    async def _run():
        # Mock crawler port
        mock_crawler = MagicMock(spec=ISxdCrawlerPort)
        sample_ann = SxdAnnouncement(
            title="Thông báo số 622/TB-SXD ngày 09/9/2026 của Sở Xây dựng Hải Phòng",
            announcement_number="622/TB-SXD",
            publish_date="09/09/2026",
            period="2026-08",
            source_url="https://soxaydung.haiphong.gov.vn/test-622",
            province="HAI_PHONG",
            attachments=[
                SxdAttachmentInfo(
                    filename="phu-luc-1.pdf",
                    download_url="https://cdn.haiphong.gov.vn/test/phu-luc-1.pdf",
                    file_type="pdf",
                ),
                SxdAttachmentInfo(
                    filename="phu-luc-2.xlsx",
                    download_url="https://cdn.haiphong.gov.vn/test/phu-luc-2.xlsx",
                    file_type="xlsx",
                ),
            ],
        )
        mock_crawler.crawl_latest_announcements = AsyncMock(return_value=[sample_ann])
        mock_crawler.download_announcement_files = AsyncMock(
            return_value={
                "pl1_pdf": tmp_path / "TB 622" / "phu-luc-1.pdf",
                "pl2_excel": tmp_path / "TB 622" / "phu-luc-2.xlsx",
            }
        )

        # Mock ingestion engine
        mock_engine = MagicMock()
        mock_engine.ingest_to_postgres.return_value = 158

        use_case = CrawlAndSyncSxdPricesUseCase(
            crawler=mock_crawler,
            ingestion_engine=mock_engine,
            price_ref_dir=str(tmp_path),
        )

        result = await use_case.execute(max_announcements=2)

        assert result["status"] == "success"
        assert result["crawled_count"] == 1
        assert result["upserted_count"] == 158
        assert len(result["downloaded_files"]) == 1
        assert result["downloaded_files"][0]["announcement_number"] == "622/TB-SXD"
        mock_crawler.crawl_latest_announcements.assert_called_once_with(max_items=2)
        mock_crawler.download_announcement_files.assert_called_once()
        mock_engine.ingest_to_postgres.assert_called_once()

    asyncio.run(_run())


def test_api_crawl_and_sync_endpoint():
    """Kiểm tra endpoint REST API POST /v1/material-prices/crawl-and-sync."""
    with patch(
        "app.modules.inventory.application.crawl_and_sync_sxd_prices_use_case.CrawlAndSyncSxdPricesUseCase.execute"
    ) as mock_exec:
        mock_exec.return_value = {
            "status": "success",
            "message": "Đã thu thập thành công 1 kỳ thông báo từ Sở Xây dựng và đồng bộ 100 bản ghi!",
            "crawled_count": 1,
            "announcements": [],
            "downloaded_files": [],
            "upserted_count": 100,
        }

        resp = client.post(
            "/v1/material-prices/crawl-and-sync?max_announcements=2",
            headers=AUTH_HEADERS,
        )
        assert resp.status_code == 200
        data = resp.json()
        assert data["status"] == "success"
        assert data["upserted_count"] == 100
