from __future__ import annotations

import unittest
from datetime import date
from tempfile import TemporaryDirectory
from pathlib import Path
from unittest.mock import Mock

import pandas as pd

from export_historical_hourly_roi import build_hourly_report, create_workbook
from feishu_notifier import FeishuNotifier


class HistoricalHourlyRoiTest(unittest.TestCase):
    def test_builds_full_hour_grid_and_ratios(self) -> None:
        revenue_rows = pd.DataFrame(
            [
                {
                    "dt": "20260811001500",
                    "report_date": "20260811000000",
                    "daily_exposure_cnt": 50,
                    "overall_cpm": 180.0,
                    "package_cost_times_today": 5.0,
                },
                {
                    "dt": "20260811060000",
                    "report_date": "20260811054500",
                    "daily_exposure_cnt": 100,
                    "overall_cpm": 200.0,
                    "package_cost_times_today": 30.0,
                },
                {
                    "dt": "20260811061500",
                    "report_date": "20260811060000",
                    "daily_exposure_cnt": 300,
                    "overall_cpm": 240.0,
                    "package_cost_times_today": 70.0,
                },
            ]
        )
        cost_rows = pd.DataFrame(
            [
                {
                    "data_date": "20260811",
                    "hour_of_day": 0,
                    "total_uv": 2,
                    "total_cost": 10.0,
                    "total_unit_user_cost": 5.0,
                    "miniapp_uv": 1,
                    "miniapp_cost": 4.0,
                    "miniapp_unit_user_cost": 4.0,
                },
                {
                    "data_date": "20260811",
                    "hour_of_day": 6,
                    "total_uv": 10,
                    "total_cost": 50.0,
                    "total_unit_user_cost": 5.0,
                    "miniapp_uv": 5,
                    "miniapp_cost": 25.0,
                    "miniapp_unit_user_cost": 5.0,
                }
            ]
        )
        miniapp_revenue_rows = pd.DataFrame(
            [
                {
                    "data_date": "20260811",
                    "hour_of_day": 0,
                    "miniapp_revenue": 3.0,
                },
                {
                    "data_date": "20260811",
                    "hour_of_day": 6,
                    "miniapp_revenue": 40.0,
                },
            ]
        )

        report = build_hourly_report(
            revenue_rows=revenue_rows,
            cost_rows=cost_rows,
            miniapp_revenue_rows=miniapp_revenue_rows,
            start_date=date(2026, 8, 11),
            end_date=date(2026, 8, 11),
        )

        self.assertEqual(17, len(report))
        hour_6 = report[report["小时"] == "06:00"].iloc[0]
        self.assertEqual(50.0, hour_6["总投放成本"])
        self.assertEqual(25.0, hour_6["小程序投流成本"])
        self.assertEqual(70.0, hour_6["商业化收入"])
        self.assertEqual(240.0, hour_6["CPM"])
        self.assertEqual(1.4, hour_6["收入/总投放"])
        self.assertEqual(2.8, hour_6["收入/小程序成本"])
        self.assertEqual(40.0, hour_6["小程序投流收入"])
        self.assertEqual(1.6, hour_6["小程序投流收入/小程序成本"])
        self.assertEqual(1, hour_6["收入15分钟窗口数"])
        self.assertEqual(105.0, hour_6["当日累计总收入"])
        self.assertEqual(60.0, hour_6["当日累计总投放成本"])
        self.assertEqual(29.0, hour_6["当日累计小程序投流成本"])
        self.assertEqual(43.0, hour_6["当日累计小程序投流收入"])
        self.assertAlmostEqual(1.75, hour_6["当日累计收入/总投放"])
        self.assertAlmostEqual(105.0 / 29.0, hour_6["当日累计收入/小程序成本"])
        self.assertAlmostEqual(
            43.0 / 29.0,
            hour_6["当日累计小程序投流收入/小程序成本"],
        )
        self.assertEqual("06:00", report.iloc[0]["小时"])
        self.assertEqual("22:00", report.iloc[-1]["小时"])

    def test_create_workbook_writes_xlsx(self) -> None:
        report = build_hourly_report(
            revenue_rows=pd.DataFrame(),
            cost_rows=pd.DataFrame(),
            start_date=date(2026, 8, 11),
            end_date=date(2026, 8, 11),
        )

        with TemporaryDirectory() as directory:
            path = create_workbook(
                report=report,
                start_date=date(2026, 8, 11),
                end_date=date(2026, 8, 11),
                miniapp_channel="小程序投流-稳定",
                output_path=Path(directory) / "report.xlsx",
            )

            self.assertTrue(path.exists())
            self.assertGreater(path.stat().st_size, 0)

    def test_daily_cumulative_values_reset_on_the_next_date(self) -> None:
        revenue_rows = pd.DataFrame(
            [
                {
                    "dt": "20260811061500",
                    "report_date": "20260811060000",
                    "daily_exposure_cnt": 10,
                    "overall_cpm": 200.0,
                    "package_cost_times_today": 100.0,
                },
                {
                    "dt": "20260812061500",
                    "report_date": "20260812060000",
                    "daily_exposure_cnt": 10,
                    "overall_cpm": 200.0,
                    "package_cost_times_today": 20.0,
                },
            ]
        )
        miniapp_revenue_rows = pd.DataFrame(
            [
                {
                    "data_date": "20260811",
                    "hour_of_day": 6,
                    "miniapp_revenue": 80.0,
                },
                {
                    "data_date": "20260812",
                    "hour_of_day": 6,
                    "miniapp_revenue": 15.0,
                },
            ]
        )

        report = build_hourly_report(
            revenue_rows=revenue_rows,
            cost_rows=pd.DataFrame(),
            miniapp_revenue_rows=miniapp_revenue_rows,
            start_date=date(2026, 8, 11),
            end_date=date(2026, 8, 12),
        )

        day_2_hour_6 = report[
            (report["日期"] == "2026-08-12") & (report["小时"] == "06:00")
        ].iloc[0]
        self.assertEqual(20.0, day_2_hour_6["当日累计总收入"])
        self.assertEqual(15.0, day_2_hour_6["当日累计小程序投流收入"])

    def test_spreadsheet_import_defaults_to_editable_link(self) -> None:
        notifier = FeishuNotifier()
        notifier._require_drive_config = Mock()
        notifier._tenant_token = Mock(return_value="tenant-token")
        notifier._upload = Mock(return_value="file-token")
        notifier._import_sheet = Mock(
            return_value={"url": "https://example.test/sheet", "token": "sheet-token"}
        )
        notifier._set_read_permission = Mock()
        notifier._set_edit_permission = Mock()

        url = notifier.import_spreadsheet(Path("report.xlsx"))

        self.assertEqual("https://example.test/sheet", url)
        notifier._set_edit_permission.assert_called_once_with(
            "tenant-token", "sheet-token", "sheet"
        )
        notifier._set_read_permission.assert_not_called()


if __name__ == "__main__":
    unittest.main()
