import 'package:flutter_test/flutter_test.dart';
import 'package:pomodoro_app/models/pomodoro_state.dart';

void main() {
  group('TimerStyle', () {
    test('label returns correct strings', () {
      expect(TimerStyle.pomodoro.label, 'Pomodoro');
      expect(TimerStyle.ultraradian.label, 'Ultraradian');
    });

    test('pomodoro has correct defaults', () {
      expect(TimerStyle.pomodoro.defaultWorkMinutes, 25);
      expect(TimerStyle.pomodoro.defaultShortBreakMinutes, 5);
      expect(TimerStyle.pomodoro.defaultLongBreakMinutes, 15);
      expect(TimerStyle.pomodoro.defaultPomodorosPerCycle, 4);
    });

    test('ultraradian has correct defaults', () {
      expect(TimerStyle.ultraradian.defaultWorkMinutes, 90);
      expect(TimerStyle.ultraradian.defaultShortBreakMinutes, 30);
      expect(TimerStyle.ultraradian.defaultLongBreakMinutes, 30);
      expect(TimerStyle.ultraradian.defaultPomodorosPerCycle, 1);
    });
  });

  group('PomodoroMode', () {
    test('label returns correct strings', () {
      expect(PomodoroMode.work.label, 'Work');
      expect(PomodoroMode.shortBreak.label, 'Short Break');
      expect(PomodoroMode.longBreak.label, 'Long Break');
    });
  });

  group('PomodoroState.initial', () {
    test('creates default state', () {
      final state = PomodoroState.initial();
      expect(state.mode, PomodoroMode.work);
      expect(state.remainingSeconds, 25 * 60);
      expect(state.totalSeconds, 25 * 60);
      expect(state.isRunning, false);
      expect(state.completedPomodoros, 0);
      expect(state.pomodorosPerCycle, 4);
    });

    test('creates state with custom durations', () {
      final state = PomodoroState.initial(
        workMinutes: 30,
        shortBreakMinutes: 10,
        longBreakMinutes: 20,
        pomodorosPerCycle: 3,
      );
      expect(state.remainingSeconds, 30 * 60);
      expect(state.totalSeconds, 30 * 60);
      expect(state.pomodorosPerCycle, 3);
    });
  });

  group('PomodoroState.progress', () {
    test('returns 0.0 at start', () {
      final state = PomodoroState.initial();
      expect(state.progress, 0.0);
    });

    test('returns 0.5 at halfway', () {
      final state = PomodoroState.initial().copyWith(
        remainingSeconds: 25 * 30, // half of 25*60
      );
      expect(state.progress, closeTo(0.5, 0.001));
    });

    test('returns 1.0 when totalSeconds is 0', () {
      final state = PomodoroState.initial().copyWith(
        totalSeconds: 0,
        remainingSeconds: 0,
      );
      expect(state.progress, 1.0);
    });

    test('returns close to 1.0 at end', () {
      final state = PomodoroState.initial().copyWith(remainingSeconds: 0);
      expect(state.progress, 1.0);
    });
  });

  group('PomodoroState.formattedTime', () {
    test('formats full time correctly', () {
      final state = PomodoroState.initial(); // 25:00
      expect(state.formattedTime, '25:00');
    });

    test('formats single-digit minutes with padding', () {
      final state = PomodoroState.initial().copyWith(remainingSeconds: 5 * 60 + 30);
      expect(state.formattedTime, '05:30');
    });

    test('formats zero correctly', () {
      final state = PomodoroState.initial().copyWith(remainingSeconds: 0);
      expect(state.formattedTime, '00:00');
    });

    test('formats seconds with padding', () {
      final state = PomodoroState.initial().copyWith(remainingSeconds: 60 + 5);
      expect(state.formattedTime, '01:05');
    });
  });

  group('PomodoroState.copyWith', () {
    test('copies with mode change', () {
      final original = PomodoroState.initial();
      final copy = original.copyWith(mode: PomodoroMode.shortBreak);
      expect(copy.mode, PomodoroMode.shortBreak);
      expect(copy.remainingSeconds, original.remainingSeconds);
    });

    test('preserves values when no parameters given', () {
      final original = PomodoroState.initial();
      final copy = original.copyWith();
      expect(copy, original);
    });
  });

  group('PomodoroState.modeDisplayLabel', () {
    test('returns mode label when pomodorosPerCycle > 1', () {
      final state = PomodoroState.initial();
      expect(state.modeDisplayLabel, 'Work');

      final breakState = state.copyWith(mode: PomodoroMode.shortBreak);
      expect(breakState.modeDisplayLabel, 'Short Break');

      final longBreakState = state.copyWith(mode: PomodoroMode.longBreak);
      expect(longBreakState.modeDisplayLabel, 'Long Break');
    });

    test('returns Break when pomodorosPerCycle is 1 and not work', () {
      final state = PomodoroState.initial(pomodorosPerCycle: 1);
      expect(state.modeDisplayLabel, 'Work');

      final breakState = state.copyWith(mode: PomodoroMode.shortBreak);
      expect(breakState.modeDisplayLabel, 'Break');

      final longBreakState = state.copyWith(mode: PomodoroMode.longBreak);
      expect(longBreakState.modeDisplayLabel, 'Break');
    });
  });

  group('PomodoroState equality', () {
    test('equal states are ==', () {
      final a = PomodoroState.initial();
      final b = PomodoroState.initial();
      expect(a, b);
      expect(a.hashCode, b.hashCode);
    });

    test('different states are !=', () {
      final a = PomodoroState.initial();
      final b = a.copyWith(remainingSeconds: 100);
      expect(a, isNot(b));
    });

    test('identical references are ==', () {
      final a = PomodoroState.initial();
      // ignore: prefer_const_declarations
      final b = a;
      expect(identical(a, b), true);
      expect(a, b);
    });

    test('different type is !=', () {
      final a = PomodoroState.initial();
      // ignore: unrelated_type_equality_checks
      expect(a == 'not a state', false);
    });
  });
}
