"""Tests for edinet_mcp._validation."""

from __future__ import annotations

import datetime
import warnings

import pytest

from edinet_mcp._validation import (
    FinancialDataWarning,
    _check_abnormal_values,
    _check_balance_sheet_equation,
    _check_critical_items,
    _check_income_statement_consistency,
    validate_financial_statement,
)
from edinet_mcp.models import (
    AccountingStandard,
    DocType,
    Filing,
    FinancialStatement,
    StatementData,
)


def _make_statement(
    bs_data: dict[str, dict[str, float | None]] | None = None,
    pl_data: dict[str, dict[str, float | None]] | None = None,
    cf_data: dict[str, dict[str, float | None]] | None = None,
) -> FinancialStatement:
    """Helper to create a FinancialStatement for testing."""
    bs_items = []
    if bs_data:
        for label, values in bs_data.items():
            bs_items.append({"科目": label, **values})

    pl_items = []
    if pl_data:
        for label, values in pl_data.items():
            pl_items.append({"科目": label, **values})

    cf_items = []
    if cf_data:
        for label, values in cf_data.items():
            cf_items.append({"科目": label, **values})

    # Create a mock Filing
    filing = Filing(
        doc_id="S100TEST",
        edinet_code="E00000",
        company_name="Test Company",
        doc_type=DocType.ANNUAL_REPORT,
        filing_date=datetime.date(2024, 6, 20),
    )

    return FinancialStatement(
        filing=filing,
        balance_sheet=StatementData(items=bs_items),
        income_statement=StatementData(items=pl_items),
        cash_flow_statement=StatementData(items=cf_items),
        accounting_standard=AccountingStandard.JGAAP,
    )


class TestBalanceSheetEquation:
    def test_balanced_statement_no_warning(self) -> None:
        """Balanced BS (Assets = Liabilities + Equity) should not warn."""
        stmt = _make_statement(
            bs_data={
                "総資産": {"当期": 1000000},
                "負債純資産合計": {"当期": 1000000},
            }
        )

        with warnings.catch_warnings():
            warnings.simplefilter("error", FinancialDataWarning)
            _check_balance_sheet_equation(stmt)  # Should not raise

    def test_small_diff_no_warning(self) -> None:
        """Small differences (< 1 million yen) should not warn."""
        stmt = _make_statement(
            bs_data={
                "総資産": {"当期": 1000000},
                "負債純資産合計": {"当期": 1000500},  # 500k diff
            }
        )

        with warnings.catch_warnings():
            warnings.simplefilter("error", FinancialDataWarning)
            _check_balance_sheet_equation(stmt)  # Should not raise

    def test_large_diff_warns(self) -> None:
        """Large differences (> 1 million yen) should warn."""
        stmt = _make_statement(
            bs_data={
                "総資産": {"当期": 1000000},
                "負債純資産合計": {"当期": 1002000},  # 2M diff
            }
        )

        with pytest.warns(FinancialDataWarning, match="Balance sheet imbalance"):
            _check_balance_sheet_equation(stmt)

    def test_missing_fields_no_warning(self) -> None:
        """Missing fields should not cause warnings."""
        stmt = _make_statement(bs_data={"総資産": {"当期": 1000000}})

        with warnings.catch_warnings():
            warnings.simplefilter("error", FinancialDataWarning)
            _check_balance_sheet_equation(stmt)  # Should not raise


class TestIncomeStatementConsistency:
    def test_consistent_gross_profit_no_warning(self) -> None:
        """Gross Profit = Revenue - COGS should not warn."""
        stmt = _make_statement(
            pl_data={
                "売上高": {"当期": 100000},
                "売上原価": {"当期": 60000},
                "売上総利益": {"当期": 40000},
            }
        )

        with warnings.catch_warnings():
            warnings.simplefilter("error", FinancialDataWarning)
            _check_income_statement_consistency(stmt)

    def test_inconsistent_gross_profit_warns(self) -> None:
        """Inconsistent Gross Profit should warn."""
        stmt = _make_statement(
            pl_data={
                "売上高": {"当期": 100000},
                "売上原価": {"当期": 60000},
                "売上総利益": {"当期": 42000},  # Should be 40000
            }
        )

        with pytest.warns(FinancialDataWarning, match="Income statement inconsistency"):
            _check_income_statement_consistency(stmt)

    def test_missing_fields_no_warning(self) -> None:
        """Missing fields should not cause warnings."""
        stmt = _make_statement(pl_data={"売上高": {"当期": 100000}})

        with warnings.catch_warnings():
            warnings.simplefilter("error", FinancialDataWarning)
            _check_income_statement_consistency(stmt)


class TestAbnormalValues:
    def test_positive_assets_no_warning(self) -> None:
        """Positive total assets should not warn."""
        stmt = _make_statement(bs_data={"総資産": {"当期": 1000000}})

        with warnings.catch_warnings():
            warnings.simplefilter("error", FinancialDataWarning)
            _check_abnormal_values(stmt)

    def test_negative_assets_warns(self) -> None:
        """Negative total assets should warn."""
        stmt = _make_statement(bs_data={"総資産": {"当期": -1000}})

        with pytest.warns(FinancialDataWarning, match="Negative total assets"):
            _check_abnormal_values(stmt)

    def test_negative_equity_warns(self) -> None:
        """Negative equity should warn."""
        stmt = _make_statement(bs_data={"純資産": {"当期": -500}})

        with pytest.warns(FinancialDataWarning, match="Negative equity"):
            _check_abnormal_values(stmt)


class TestCriticalItems:
    def test_has_revenue_no_warning(self) -> None:
        """Statement with revenue should not warn."""
        stmt = _make_statement(
            pl_data={"売上高": {"当期": 100000}},
            bs_data={"総資産": {"当期": 500000}},
        )

        with warnings.catch_warnings():
            warnings.simplefilter("error", FinancialDataWarning)
            _check_critical_items(stmt)

    def test_missing_revenue_warns(self) -> None:
        """Missing revenue should warn."""
        stmt = _make_statement(pl_data={}, bs_data={"総資産": {"当期": 500000}})

        with pytest.warns(FinancialDataWarning, match="No revenue line item"):
            _check_critical_items(stmt)

    def test_missing_total_assets_warns(self) -> None:
        """Missing total assets should warn."""
        stmt = _make_statement(pl_data={"売上高": {"当期": 100000}}, bs_data={})

        with pytest.warns(FinancialDataWarning, match="No total assets"):
            _check_critical_items(stmt)


class TestValidateFinancialStatement:
    def test_comprehensive_validation(self) -> None:
        """Full validation should run all checks."""
        stmt = _make_statement(
            bs_data={
                "総資産": {"当期": 1000000},
                "負債純資産合計": {"当期": 1000000},
                "純資産": {"当期": 400000},
            },
            pl_data={
                "売上高": {"当期": 100000},
                "売上原価": {"当期": 60000},
                "売上総利益": {"当期": 40000},
            },
        )

        # Should not raise any warnings for a valid statement
        with warnings.catch_warnings():
            warnings.simplefilter("error", FinancialDataWarning)
            validate_financial_statement(stmt)

    def test_multiple_issues_multiple_warnings(self) -> None:
        """Statement with multiple issues should generate multiple warnings."""
        stmt = _make_statement(
            bs_data={
                "総資産": {"当期": -1000},  # Negative assets
                "純資産": {"当期": -500},  # Negative equity
            },
            pl_data={},  # Missing revenue
        )

        with pytest.warns(FinancialDataWarning) as record:
            validate_financial_statement(stmt)

        # Should have at least 3 warnings (negative assets, negative equity, missing revenue)
        assert len(record) >= 3
