# -*- coding: utf-8 -*-
"""
DWS 任务 birthday 字段恢复测试

验证需求 4.4：DWS 任务从 dim_member.birthday 读取生日字段并写入 DWS 目标表。
纯单元测试，使用 FakeDB/Mock，不涉及真实数据库连接。
"""

import pytest
from datetime import date
from decimal import Decimal
from unittest.mock import MagicMock

import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from tests.unit.task_test_utils import FakeDBOperations


# ---------------------------------------------------------------------------
# Helper: 创建 MemberVisitTask 实例
# ---------------------------------------------------------------------------

def _create_member_visit_task():
    from tasks.dws.member_visit_task import MemberVisitTask
    mock_config = MagicMock()
    mock_config.get.side_effect = lambda key, default=None: (
        1 if key == "app.tenant_id" else default
    )
    db = FakeDBOperations()
    return MemberVisitTask(mock_config, db, MagicMock(), MagicMock()), db


def _create_member_consumption_task():
    from tasks.dws.member_consumption_task import MemberConsumptionTask
    mock_config = MagicMock()
    mock_config.get.side_effect = lambda key, default=None: (
        1 if key == "app.tenant_id" else default
    )
    db = FakeDBOperations()
    return MemberConsumptionTask(mock_config, db, MagicMock(), MagicMock()), db


# ===========================================================================
# MemberVisitTask._extract_member_info — birthday 字段
# ===========================================================================

class TestMemberVisitBirthday:
    """验证 MemberVisitTask 的 birthday 提取与写入"""

    def test_extract_member_info_sql_includes_birthday(self):
        """_extract_member_info SQL 应包含 birthday 字段"""
        task, db = _create_member_visit_task()
        db.query_results.append([
            {"member_id": 100, "nickname": "张三", "mobile": "13800001111", "birthday": date(1990, 5, 15)},
        ])
        result = task._extract_member_info(site_id=1)

        # 验证 SQL 包含 birthday
        sql_executed = db.executes[0]["sql"]
        assert "birthday" in sql_executed

        # 验证返回值包含 birthday
        assert result[100]["birthday"] == date(1990, 5, 15)

    def test_extract_member_info_birthday_none(self):
        """birthday 为 None 时应正常返回"""
        task, db = _create_member_visit_task()
        db.query_results.append([
            {"member_id": 200, "nickname": "李四", "mobile": "13900002222", "birthday": None},
        ])
        result = task._extract_member_info(site_id=1)
        assert result[200]["birthday"] is None

    def test_transform_writes_member_birthday(self):
        """transform() 应将 birthday 写入 member_birthday 字段"""
        task, db = _create_member_visit_task()

        extracted = {
            "settlements": [
                {
                    "member_id": 100,
                    "order_settle_id": 1001,
                    "visit_date": date(2026, 2, 20),
                    "create_time": "2026-02-20 14:00:00",
                    "table_id": 10,
                    "table_charge_money": Decimal("50.00"),
                    "goods_money": Decimal("30.00"),
                    "assistant_pd_money": Decimal("20.00"),
                    "assistant_cx_money": Decimal("10.00"),
                    "consume_money": Decimal("110.00"),
                    "pay_amount": Decimal("100.00"),
                    "balance_amount": Decimal("0"),
                    "gift_card_amount": Decimal("0"),
                    "coupon_amount": Decimal("10.00"),
                    "discount_money": Decimal("0"),
                    "free_money": Decimal("0"),
                },
            ],
            "assistant_services": [],
            "member_info": {
                100: {
                    "member_id": 100,
                    "nickname": "张三",
                    "mobile": "13800001111",
                    "birthday": date(1990, 5, 15),
                },
            },
            "table_info": {
                10: {"table_id": 10, "table_name": "1号台", "area_name": "大厅"},
            },
            "table_fee_durations": [],
            "site_id": 1,
        }

        from tasks.dws.base_dws_task import TaskContext
        from datetime import datetime
        ctx = TaskContext(
            store_id=1,
            window_start=datetime(2026, 2, 20),
            window_end=datetime(2026, 2, 20, 23, 59, 59),
            window_minutes=1440,
        )

        results = task.transform(extracted, ctx)
        assert len(results) == 1
        assert results[0]["member_birthday"] == date(1990, 5, 15)

    def test_transform_member_birthday_none_when_no_birthday(self):
        """会员无 birthday 时 member_birthday 应为 None"""
        task, db = _create_member_visit_task()

        extracted = {
            "settlements": [
                {
                    "member_id": 300,
                    "order_settle_id": 3001,
                    "visit_date": date(2026, 2, 20),
                    "create_time": "2026-02-20 15:00:00",
                    "table_id": 10,
                    "table_charge_money": Decimal("0"),
                    "goods_money": Decimal("0"),
                    "assistant_pd_money": Decimal("0"),
                    "assistant_cx_money": Decimal("0"),
                    "consume_money": Decimal("0"),
                    "pay_amount": Decimal("0"),
                    "balance_amount": Decimal("0"),
                    "gift_card_amount": Decimal("0"),
                    "coupon_amount": Decimal("0"),
                    "discount_money": Decimal("0"),
                    "free_money": Decimal("0"),
                },
            ],
            "assistant_services": [],
            "member_info": {
                300: {"member_id": 300, "nickname": "王五", "mobile": None, "birthday": None},
            },
            "table_info": {10: {"table_id": 10, "table_name": "1号台", "area_name": None}},
            "table_fee_durations": [],
            "site_id": 1,
        }

        from tasks.dws.base_dws_task import TaskContext
        from datetime import datetime
        ctx = TaskContext(
            store_id=1,
            window_start=datetime(2026, 2, 20),
            window_end=datetime(2026, 2, 20, 23, 59, 59),
            window_minutes=1440,
        )
        results = task.transform(extracted, ctx)
        assert results[0]["member_birthday"] is None


# ===========================================================================
# MemberConsumptionTask._extract_member_info — birthday 字段
# ===========================================================================

class TestMemberConsumptionBirthday:
    """验证 MemberConsumptionTask 的 birthday 提取"""

    def test_extract_member_info_sql_includes_birthday(self):
        """_extract_member_info SQL 应包含 birthday 字段"""
        task, db = _create_member_consumption_task()
        db.query_results.append([
            {
                "member_id": 100, "nickname": "张三", "mobile": "13800001111",
                "member_card_grade_name": "金卡", "register_date": date(2025, 1, 1),
                "recharge_money_sum": Decimal("500.00"), "birthday": date(1995, 8, 20),
            },
        ])
        result = task._extract_member_info(site_id=1)

        sql_executed = db.executes[0]["sql"]
        assert "birthday" in sql_executed
        assert result[100]["birthday"] == date(1995, 8, 20)

    def test_extract_member_info_birthday_none(self):
        """birthday 为 None 时应正常返回"""
        task, db = _create_member_consumption_task()
        db.query_results.append([
            {
                "member_id": 200, "nickname": "李四", "mobile": None,
                "member_card_grade_name": None, "register_date": None,
                "recharge_money_sum": Decimal("0"), "birthday": None,
            },
        ])
        result = task._extract_member_info(site_id=1)
        assert result[200]["birthday"] is None
