// connection_controller_test.dart — 连接状态机:严格三态、禁乐观显示
import 'package:flutter_test/flutter_test.dart';
import 'package:pangolin_vpn/state/connection_provider.dart';

void main() {
  // 注入极短握手时长,用真实计时器走完状态流转。
  ConnectionController make() => ConnectionController(handshake: const Duration(milliseconds: 20));

  test('初始为 off', () {
    final ctl = make();
    expect(ctl.state.phase, VpnPhase.off);
    ctl.dispose();
  });

  test('connect: off → connecting → on', () async {
    final ctl = make();
    ctl.connect();
    expect(ctl.state.phase, VpnPhase.connecting);
    await Future<void>.delayed(const Duration(milliseconds: 60));
    expect(ctl.state.phase, VpnPhase.on);
    ctl.dispose();
  });

  test('握手中再次 toggle 被忽略(禁止乐观回退)', () async {
    final ctl = make();
    ctl.toggle(); // off → connecting
    expect(ctl.state.phase, VpnPhase.connecting);
    ctl.toggle(); // connecting 中点击 → 仍 connecting
    expect(ctl.state.phase, VpnPhase.connecting);
    await Future<void>.delayed(const Duration(milliseconds: 60));
    expect(ctl.state.phase, VpnPhase.on);
    ctl.dispose();
  });

  test('on 态 toggle → off', () async {
    final ctl = make();
    ctl.connect();
    await Future<void>.delayed(const Duration(milliseconds: 60));
    expect(ctl.state.phase, VpnPhase.on);
    ctl.toggle();
    expect(ctl.state.phase, VpnPhase.off);
    ctl.dispose();
  });

  test('已连接时切换节点 → 重连(回到 connecting)', () async {
    final ctl = make();
    ctl.connect();
    await Future<void>.delayed(const Duration(milliseconds: 60));
    expect(ctl.state.phase, VpnPhase.on);
    ctl.onNodeChanged();
    expect(ctl.state.phase, VpnPhase.connecting);
    ctl.dispose();
  });

  test('on 态计时累加', () async {
    final ctl = make();
    ctl.connect();
    await Future<void>.delayed(const Duration(milliseconds: 60));
    expect(ctl.state.elapsed, Duration.zero);
    await Future<void>.delayed(const Duration(milliseconds: 1100));
    expect(ctl.state.elapsed.inSeconds, greaterThanOrEqualTo(1));
    ctl.dispose();
  });

  test('off 态切换节点不会自动连接', () {
    final ctl = make();
    ctl.onNodeChanged();
    expect(ctl.state.phase, VpnPhase.off);
    ctl.dispose();
  });
}
