"""
日报查询 API 测试（GET /api/news/reports/ 与 /api/news/events/）。

通过 mock 数据库查询层（api.report.query.*），只验证视图层
参数解析 / 默认窗口 / 响应结构 / 错误处理，不依赖真实 MySQL。
"""

from datetime import timedelta
from unittest.mock import patch

from django.test import TestCase
from django.utils import timezone
from rest_framework.test import APIClient


class NewsReportsAPITest(TestCase):
    """GET /api/news/reports/ 日报查询"""

    def setUp(self):
        self.client = APIClient()
        self.url = '/api/news/reports/'

    @patch('api.report.query.fetch_reports', return_value=[])
    def test_default_window_last_24h(self, mock_fetch):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.json(), [])
        kwargs = mock_fetch.call_args.kwargs
        now = timezone.now()
        self.assertEqual(kwargs['start_date'], (now - timedelta(hours=24)).date())
        self.assertEqual(kwargs['end_date'], now.date())
        self.assertIsNone(kwargs['report_type'])
        self.assertIsNone(kwargs['report_id'])

    @patch('api.report.query.fetch_reports',
           return_value=[{'id': 1, 'report_date': '2026-08-01', 'report_type': 'finance'}])
    def test_report_type_and_date_range(self, mock_fetch):
        resp = self.client.get(self.url, {
            'report_type': 'finance',
            'start_date': '2026-07-01',
            'end_date': '2026-08-03',
        })
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(len(resp.json()), 1)
        kwargs = mock_fetch.call_args.kwargs
        self.assertEqual(kwargs['report_type'], 'finance')
        self.assertEqual(str(kwargs['start_date']), '2026-07-01')
        self.assertEqual(str(kwargs['end_date']), '2026-08-03')

    @patch('api.report.query.fetch_reports')
    def test_detail_by_id(self, mock_fetch):
        mock_fetch.return_value = {
            'id': 10, 'report_date': '2026-08-03', 'report_type': 'finance',
            'events': [{'id': 1, 'title': '事件一'}],
        }
        resp = self.client.get(self.url, {'id': '10'})
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.json()['id'], 10)
        self.assertEqual(mock_fetch.call_args.kwargs['report_id'], 10)

    @patch('api.report.query.fetch_reports', return_value=None)
    def test_detail_not_found(self, mock_fetch):
        resp = self.client.get(self.url, {'id': '99999'})
        self.assertEqual(resp.status_code, 404)
        self.assertIn('error', resp.json())

    def test_invalid_report_type(self):
        resp = self.client.get(self.url, {'report_type': 'xxx'})
        self.assertEqual(resp.status_code, 400)

    def test_invalid_date_format(self):
        resp = self.client.get(self.url, {'start_date': '2026/07/01'})
        self.assertEqual(resp.status_code, 400)

    def test_invalid_id(self):
        resp = self.client.get(self.url, {'id': 'abc'})
        self.assertEqual(resp.status_code, 400)

    def test_non_positive_id(self):
        resp = self.client.get(self.url, {'id': '0'})
        self.assertEqual(resp.status_code, 400)

    @patch('api.report.query.fetch_reports', side_effect=RuntimeError('db down'))
    def test_query_error_500(self, mock_fetch):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 500)
        self.assertIn('error', resp.json())


class NewsEventsAPITest(TestCase):
    """GET /api/news/events/ 重要事件聚合"""

    def setUp(self):
        self.client = APIClient()
        self.url = '/api/news/events/'

    @patch('api.report.query.fetch_important_events', return_value=[])
    def test_defaults(self, mock_fetch):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.json(), [])
        kwargs = mock_fetch.call_args.kwargs
        self.assertEqual(kwargs['days'], 7)
        self.assertEqual(kwargs['importance'], 4)
        self.assertEqual(kwargs['limit'], 100)
        self.assertIsNone(kwargs['report_type'])
        self.assertIsNone(kwargs['section'])

    @patch('api.report.query.fetch_important_events',
           return_value=[{'id': 1, 'title': '重要事件', 'importance': 5}])
    def test_filters(self, mock_fetch):
        resp = self.client.get(self.url, {
            'days': '3', 'importance': '5',
            'report_type': 'intl', 'section': 'intl', 'limit': '10',
        })
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(len(resp.json()), 1)
        kwargs = mock_fetch.call_args.kwargs
        self.assertEqual(kwargs['days'], 3)
        self.assertEqual(kwargs['importance'], 5)
        self.assertEqual(kwargs['limit'], 10)
        self.assertEqual(kwargs['report_type'], 'intl')
        self.assertEqual(kwargs['section'], 'intl')

    def test_invalid_days(self):
        resp = self.client.get(self.url, {'days': 'abc'})
        self.assertEqual(resp.status_code, 400)

    def test_days_out_of_range(self):
        resp = self.client.get(self.url, {'days': '0'})
        self.assertEqual(resp.status_code, 400)

    def test_invalid_importance(self):
        resp = self.client.get(self.url, {'importance': '9'})
        self.assertEqual(resp.status_code, 400)

    def test_invalid_section(self):
        resp = self.client.get(self.url, {'section': 'foo'})
        self.assertEqual(resp.status_code, 400)

    def test_invalid_report_type(self):
        resp = self.client.get(self.url, {'report_type': 'xxx'})
        self.assertEqual(resp.status_code, 400)

    @patch('api.report.query.fetch_important_events', side_effect=RuntimeError('db down'))
    def test_query_error_500(self, mock_fetch):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 500)
        self.assertIn('error', resp.json())
