import unittest
import sys
import types
from datetime import datetime, timezone
from zoneinfo import ZoneInfo

import pandas as pd

stub = types.ModuleType('pydantic_settings')


class BaseSettings:
    def __init__(self, **kwargs):
        for name, value in self.__class__.__dict__.items():
            if name.isupper():
                setattr(self, name, kwargs.get(name, value))


stub.BaseSettings = BaseSettings
sys.modules.setdefault('pydantic_settings', stub)

from cache.vessel_store import VesselStore
from time_bucket import compute_incremental_window_start, compute_initial_window_start, compute_safe_bucket


class TimeBucketRuleTest(unittest.TestCase):
    def test_safe_bucket_uses_delay_then_floors_to_5m(self):
        now = datetime(2026, 4, 2, 15, 14, 0, tzinfo=ZoneInfo('Asia/Seoul'))
        self.assertEqual(compute_safe_bucket(now), datetime(2026, 4, 2, 15, 0, 0))

    def test_incremental_window_includes_overlap_buckets(self):
        last_bucket = datetime(2026, 4, 2, 15, 0, 0)
        self.assertEqual(compute_incremental_window_start(last_bucket), datetime(2026, 4, 2, 14, 45, 0))

    def test_initial_window_start_anchors_to_safe_bucket(self):
        safe_bucket = datetime(2026, 4, 2, 15, 0, 0)
        self.assertEqual(compute_initial_window_start(24, safe_bucket), datetime(2026, 4, 1, 15, 0, 0))

    def test_merge_incremental_prefers_newer_overlap_rows(self):
        store = VesselStore()
        store._tracks = {
            '412000001': pd.DataFrame([
                {
                    'mmsi': '412000001',
                    'timestamp': pd.Timestamp('2026-04-02T00:01:00Z'),
                    'time_bucket': datetime(2026, 4, 2, 9, 0, 0),
                    'lat': 30.0,
                    'lon': 120.0,
                    'raw_sog': 1.0,
                },
                {
                    'mmsi': '412000001',
                    'timestamp': pd.Timestamp('2026-04-02T00:02:00Z'),
                    'time_bucket': datetime(2026, 4, 2, 9, 0, 0),
                    'lat': 30.1,
                    'lon': 120.1,
                    'raw_sog': 1.0,
                },
            ])
        }
        df_new = pd.DataFrame([
            {
                'mmsi': '412000001',
                'timestamp': pd.Timestamp('2026-04-02T00:02:00Z'),
                'time_bucket': datetime(2026, 4, 2, 9, 0, 0),
                'lat': 30.2,
                'lon': 120.2,
                'raw_sog': 2.0,
            },
            {
                'mmsi': '412000001',
                'timestamp': pd.Timestamp('2026-04-02T00:03:00Z'),
                'time_bucket': datetime(2026, 4, 2, 9, 5, 0),
                'lat': 30.3,
                'lon': 120.3,
                'raw_sog': 2.0,
            },
        ])

        store.merge_incremental(df_new)

        merged = store._tracks['412000001']
        self.assertEqual(len(merged), 3)
        replacement = merged.loc[merged['timestamp'] == pd.Timestamp('2026-04-02T00:02:00Z')].iloc[0]
        self.assertEqual(float(replacement['lat']), 30.2)
        self.assertEqual(float(replacement['lon']), 120.2)


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