import 'package:asciineverdie/src/core/engine/return_rewards_service.dart';
import 'package:asciineverdie/src/core/model/treasure_chest.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  // 싱글톤(singleton) 인스턴스 사용
  final service = ReturnRewardsService.instance;

  // 기준 시각(base time) 설정
  final baseTime = DateTime(2026, 3, 9, 12, 0, 0);

  group('ReturnRewardsService', () {
    group('calculateReward', () {
      test('lastPlayTime이 null이면 보상 없음', () {
        final result = service.calculateReward(
          lastPlayTime: null,
          currentTime: baseTime,
          isPaidUser: false,
        );

        expect(result.hasReward, isFalse);
        expect(result.hoursAway, equals(0));
        expect(result.chestCount, equals(0));
        expect(result.bonusChestCount, equals(0));
      });

      test('1시간 미만이면 보상 없음', () {
        // 30분 전 플레이
        final lastPlay = baseTime.subtract(const Duration(minutes: 30));

        final result = service.calculateReward(
          lastPlayTime: lastPlay,
          currentTime: baseTime,
          isPaidUser: false,
        );

        expect(result.hasReward, isFalse);
        expect(result.chestCount, equals(0));
      });

      test('정확히 4시간이면 상자(chest) 1개', () {
        final lastPlay = baseTime.subtract(const Duration(hours: 4));

        final result = service.calculateReward(
          lastPlayTime: lastPlay,
          currentTime: baseTime,
          isPaidUser: false,
        );

        expect(result.hasReward, isTrue);
        expect(result.chestCount, equals(1));
        expect(result.hoursAway, equals(4));
      });

      test('12시간이면 상자 3개', () {
        final lastPlay = baseTime.subtract(const Duration(hours: 12));

        final result = service.calculateReward(
          lastPlayTime: lastPlay,
          currentTime: baseTime,
          isPaidUser: false,
        );

        expect(result.hasReward, isTrue);
        expect(result.chestCount, equals(3));
        expect(result.hoursAway, equals(12));
      });

      test('24시간 초과 시 maxHoursAway로 제한(cap)', () {
        // 48시간 전 플레이 → effectiveHours = 24
        final lastPlay = baseTime.subtract(const Duration(hours: 48));

        final result = service.calculateReward(
          lastPlayTime: lastPlay,
          currentTime: baseTime,
          isPaidUser: false,
        );

        // 24 ~/ 4 = 6 → 무료 유저 최대(maxChestsFree) 5개
        expect(result.chestCount, equals(5));
        expect(result.hoursAway, equals(48));
      });

      test('무료 유저(free user) 최대 상자 5개', () {
        // 20시간 → 20 ~/ 4 = 5개
        final lastPlay = baseTime.subtract(const Duration(hours: 20));

        final result = service.calculateReward(
          lastPlayTime: lastPlay,
          currentTime: baseTime,
          isPaidUser: false,
        );

        expect(result.chestCount, equals(5));
      });

      test('유료 유저(paid user) 최대 상자 10개', () {
        // 유료 유저: 24시간 → creditedHours = 48 → cap 24
        // 24 ~/ 4 = 6개 (maxChestsPaid 10 이내)
        final lastPlay = baseTime.subtract(const Duration(hours: 48));

        final result = service.calculateReward(
          lastPlayTime: lastPlay,
          currentTime: baseTime,
          isPaidUser: true,
        );

        // 48시간, 유료 2배 → 96 → cap 24 → 24 ~/ 4 = 6
        expect(result.chestCount, equals(6));
        expect(result.chestCount, lessThanOrEqualTo(10));
      });

      test('유료 유저 오프라인 시간 2배 인정 (4시간 → 8시간 → 상자 2개)', () {
        // 실제 4시간, 유료 2배 → creditedHours = 8
        // 8 ~/ 4 = 2개
        final lastPlay = baseTime.subtract(const Duration(hours: 4));

        final result = service.calculateReward(
          lastPlayTime: lastPlay,
          currentTime: baseTime,
          isPaidUser: true,
        );

        expect(result.chestCount, equals(2));
      });

      test('유료 유저 2배 적용 후에도 24시간으로 제한', () {
        // 14시간 → creditedHours = 28 → cap 24
        // 24 ~/ 4 = 6개
        final lastPlay = baseTime.subtract(const Duration(hours: 14));

        final result = service.calculateReward(
          lastPlayTime: lastPlay,
          currentTime: baseTime,
          isPaidUser: true,
        );

        // 14 * 2 = 28 → capped to 24 → 24 ~/ 4 = 6
        expect(result.chestCount, equals(6));
      });
    });

    group('bonusChestCount', () {
      test('bonusChestCount는 chestCount와 동일', () {
        final lastPlay = baseTime.subtract(const Duration(hours: 8));

        final result = service.calculateReward(
          lastPlayTime: lastPlay,
          currentTime: baseTime,
          isPaidUser: false,
        );

        // 8 ~/ 4 = 2
        expect(result.chestCount, equals(2));
        expect(result.bonusChestCount, equals(result.chestCount));
      });
    });

    group('claimBasicReward', () {
      test('보상 없는 경우 빈 목록(empty list) 반환', () {
        const reward = ReturnChestReward(
          hoursAway: 0,
          chestCount: 0,
          bonusChestCount: 0,
        );

        final result = service.claimBasicReward(reward, 10);

        expect(result, isEmpty);
      });
    });

    group('formatHoursAway', () {
      test('24시간 미만은 시간만 표시', () {
        expect(service.formatHoursAway(5), equals('5h'));
        expect(service.formatHoursAway(1), equals('1h'));
        expect(service.formatHoursAway(23), equals('23h'));
      });

      test('정확히 24시간은 일(day) 단위 표시', () {
        expect(service.formatHoursAway(24), equals('1d'));
        expect(service.formatHoursAway(48), equals('2d'));
      });

      test('일 + 시간 혼합 표시', () {
        expect(service.formatHoursAway(25), equals('1d 1h'));
        expect(service.formatHoursAway(50), equals('2d 2h'));
        expect(service.formatHoursAway(30), equals('1d 6h'));
      });
    });
  });
}
