// connect_page.dart — 连接页(三端：desktop 居中单列 / tablet 双栏 / mobile 单列滚动)
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../bridge/vpn_bridge.dart';
import '../core/responsive/form_factor.dart';
import '../l10n/app_text.dart';
import '../models/node.dart';
import '../pangolin_theme.dart';
import '../state/app_providers.dart';
import '../state/connection_provider.dart';
import '../state/nodes_provider.dart';
import '../state/quota_provider.dart';
import '../widgets/app_top_bar.dart';
import '../widgets/connect_button.dart';
import '../widgets/country_code.dart';
import '../widgets/pangolin_icons.dart';
import '../widgets/quota_card.dart';

class ConnectPage extends ConsumerWidget {
  const ConnectPage({super.key, required this.isWide, required this.onOpenNodes});

  final bool isWide;
  final VoidCallback onOpenNodes;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final c = context.pangolin;
    final t = ref.watch(appTextProvider);
    final conn = ref.watch(connectionProvider);
    final node = ref.watch(effectiveNodeProvider);
    final smart = ref.watch(isSmartSelectProvider);
    final isFree = ref.watch(isFreePlanProvider);
    final quota = ref.watch(quotaProvider);
    final stats = ref.watch(vpnStatsProvider).valueOrNull;
    final down = _speed(stats?.downloadSpeed);
    final up = _speed(stats?.uploadSpeed);
    // 延迟来源:连接后优先用内核 urltest 实测(代理真实 RTT);urltest 还没探过时
    // 回退用节点页的 TCP 探针 ping,尽量不显示 —。都没有才 —。
    var livePing = conn.phase == VpnPhase.on ? _bestUrltest(stats) : node.ping;
    if (livePing <= 0) livePing = node.ping;
    final pingLabel = livePing > 0 ? '${livePing}ms' : '—';
    final latencyValue = livePing > 0 ? '$livePing' : '—';

    final caption = switch (conn.phase) {
      VpnPhase.off => t.capOff,
      VpnPhase.connecting => t.capConnecting,
      VpnPhase.on => t.capOn,
    };

    final button = ConnectButton(
      phase: conn.phase,
      elapsed: conn.elapsed,
      offLabel: t.connectNow,
      secureLabel: t.secure,
      onTap: () => ref.read(connectionProvider.notifier).toggle(),
    );

    final captionWidget = Column(mainAxisSize: MainAxisSize.min, children: [
      Text(caption, style: PangolinText.body.copyWith(color: c.fg2, fontWeight: FontWeight.w600)),
      if (conn.error != null) ...[
        const SizedBox(height: 8),
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 24),
          child: Text(conn.error!,
              textAlign: TextAlign.center,
              style: PangolinText.caption.copyWith(color: c.danger, fontWeight: FontWeight.w500)),
        ),
      ],
    ]);

    final infoChildren = <Widget>[
      if (isFree)
        QuotaCard(quota: quota, t: t, onWatchAd: () => ref.read(quotaProvider.notifier).watchAd()),
      if (conn.phase == VpnPhase.on) _SpeedRow(t: t, down: down, up: up, latency: latencyValue),
      _CurrentNodeCard(t: t, node: node, smart: smart, pingLabel: pingLabel, showLabel: isWide, onTap: onOpenNodes),
    ];

    final statusTrailing = Text(
      conn.phase == VpnPhase.on ? t.online : t.offline,
      style: PangolinText.mono.copyWith(
          fontSize: 12,
          color: conn.phase == VpnPhase.on ? c.success : c.fg3,
          fontWeight: FontWeight.w600),
    );

    if (context.formFactor == FormFactor.desktop) {
      // 桌面居中单列（对照 ui_kits/desktop/dapp.jsx DConnect）
      return Center(
        child: SingleChildScrollView(
          padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 40),
          child: Column(mainAxisSize: MainAxisSize.min, children: [
            ConnectButton(
              phase: conn.phase,
              elapsed: conn.elapsed,
              offLabel: t.connectNow,
              secureLabel: t.secure,
              size: 176,
              onTap: () => ref.read(connectionProvider.notifier).toggle(),
            ),
            const SizedBox(height: 24),
            Text(caption,
                textAlign: TextAlign.center,
                style: PangolinText.display.copyWith(color: c.fg1, fontSize: 22, fontWeight: FontWeight.w700)),
            const SizedBox(height: 10),
            if (conn.error != null) ...[
              Padding(
                padding: const EdgeInsets.only(bottom: 10),
                child: Text(conn.error!,
                    textAlign: TextAlign.center,
                    style: PangolinText.caption.copyWith(color: c.danger, fontWeight: FontWeight.w500)),
              ),
            ],
            _NodePill(t: t, node: node, smart: smart, pingLabel: pingLabel),
            if (isFree) ...[
              const SizedBox(height: 24),
              SizedBox(
                width: 340,
                child: QuotaCard(quota: quota, t: t, onWatchAd: () => ref.read(quotaProvider.notifier).watchAd()),
              ),
            ],
            if (conn.phase == VpnPhase.on) ...[
              const SizedBox(height: 16),
              _SpeedRow(t: t, down: down, up: up, latency: latencyValue),
            ],
          ]),
        ),
      );
    }

    if (isWide) {
      // 宽屏双栏:左大连接键 / 右信息列(额度卡→当前节点→速率)
      return Column(children: [
        Expanded(
          child: Row(children: [
            Expanded(
              flex: 5,
              child: Center(
                child: Column(mainAxisSize: MainAxisSize.min, children: [
                  button,
                  const SizedBox(height: 24),
                  captionWidget,
                ]),
              ),
            ),
            Container(width: 1, color: c.border),
            SizedBox(
              width: 332,
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 24),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    for (final w in infoChildren) Padding(padding: const EdgeInsets.only(bottom: 14), child: w),
                  ],
                ),
              ),
            ),
          ]),
        ),
      ]);
    }

    // 窄屏单栏（可滚动，避免窗口偏矮时底部溢出）：
    // 顶栏固定，内容区用 SingleChildScrollView + ConstrainedBox(minHeight) +
    // IntrinsicHeight，高度足够时连接键居中，高度不足时整体滚动而非溢出。
    return Column(children: [
      AppTopBar(brand: t.brand, trailing: statusTrailing),
      Expanded(
        child: LayoutBuilder(
          builder: (context, constraints) => SingleChildScrollView(
            child: ConstrainedBox(
              constraints: BoxConstraints(minHeight: constraints.maxHeight),
              child: IntrinsicHeight(
                child: Column(children: [
                  Expanded(
                    child: Center(
                      child: Padding(
                        padding: const EdgeInsets.symmetric(vertical: 24),
                        child: Column(mainAxisSize: MainAxisSize.min, children: [
                          button,
                          const SizedBox(height: 24),
                          captionWidget,
                        ]),
                      ),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(20, 0, 20, 18),
                    child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
                      for (final w in infoChildren) Padding(padding: const EdgeInsets.only(bottom: 12), child: w),
                    ]),
                  ),
                ]),
              ),
            ),
          ),
        ),
      ),
    ]);
  }
}

/// 字节/秒 → 动态单位 (数值, 单位):B/s · KB/s · MB/s · GB/s(小数据也看得清)。
/// null = 未取到,显示 —。
(String, String) _speed(double? bytesPerSec) {
  if (bytesPerSec == null) return ('—', 'KB/s');
  final b = bytesPerSec;
  if (b < 1024) return (b.toStringAsFixed(0), 'B/s');
  if (b < 1024 * 1024) return ((b / 1024).toStringAsFixed(1), 'KB/s');
  if (b < 1024 * 1024 * 1024) return ((b / (1024 * 1024)).toStringAsFixed(1), 'MB/s');
  return ((b / (1024 * 1024 * 1024)).toStringAsFixed(2), 'GB/s');
}

/// 内核 urltest 各出站中的最小正延迟(ms);无则 0。
int _bestUrltest(VpnStatsEvent? s) {
  if (s == null) return 0;
  final ds = s.urltestResults.where((r) => r.delayMs > 0).map((r) => r.delayMs);
  return ds.isEmpty ? 0 : ds.reduce((a, b) => a < b ? a : b);
}

/// 实时速率行(连接成功时显示;来自内核 statsStream 实时数据)。
class _SpeedRow extends StatelessWidget {
  const _SpeedRow({required this.t, required this.down, required this.up, required this.latency});
  final AppText t;
  final (String, String) down;
  final (String, String) up;
  final String latency;

  @override
  Widget build(BuildContext context) {
    final c = context.pangolin;
    final metrics = [
      (PangolinIcons.arrowDown, t.download, down.$1, down.$2),
      (PangolinIcons.arrowUp, t.upload, up.$1, up.$2),
      (PangolinIcons.zap, t.latency, latency, 'ms'),
    ];
    return Row(children: [
      for (var i = 0; i < metrics.length; i++)
        Expanded(
          child: Padding(
            padding: EdgeInsets.only(right: i < metrics.length - 1 ? 12 : 0),
            child: Container(
              padding: const EdgeInsets.fromLTRB(13, 11, 13, 11),
              decoration: BoxDecoration(
                color: c.surface,
                borderRadius: BorderRadius.circular(PangolinRadius.lg),
                border: Border.all(color: c.border),
                boxShadow: PangolinShadow.sm,
              ),
              child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
                Row(children: [
                  Icon(metrics[i].$1, size: 13, color: c.accent),
                  const SizedBox(width: 5),
                  Flexible(
                    child: Text(metrics[i].$2,
                        overflow: TextOverflow.ellipsis,
                        style: PangolinText.caption.copyWith(color: c.fg3, fontWeight: FontWeight.w600, fontSize: 11)),
                  ),
                ]),
                const SizedBox(height: 4),
                Text.rich(TextSpan(
                  text: metrics[i].$3,
                  style: PangolinText.mono.copyWith(fontSize: 16, color: c.fg1, fontWeight: FontWeight.w500),
                  children: [TextSpan(text: ' ${metrics[i].$4}', style: PangolinText.caption.copyWith(color: c.fg3, fontSize: 10.5))],
                )),
              ]),
            ),
          ),
        ),
    ]);
  }
}

/// 当前节点卡(智能选择时展示「智能选择 + zap」)。
class _CurrentNodeCard extends StatelessWidget {
  const _CurrentNodeCard({
    required this.t,
    required this.node,
    required this.smart,
    required this.pingLabel,
    required this.showLabel,
    required this.onTap,
  });
  final AppText t;
  final Node node;
  final bool smart;
  final String pingLabel;
  final bool showLabel;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    final c = context.pangolin;
    final title = smart ? t.smartSelect : node.localizedName(t.lang);
    final sub = smart
        ? '${node.localizedName(t.lang)} · $pingLabel'
        : '${node.localizedSub(t.lang)} · $pingLabel';
    return Material(
      color: c.surface,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(PangolinRadius.lg),
        side: BorderSide(color: c.border),
      ),
      clipBehavior: Clip.antiAlias,
      child: InkWell(
        onTap: onTap,
        child: Padding(
          padding: const EdgeInsets.all(12),
          child: Row(children: [
            CountryCode(code: node.code, active: true),
            const SizedBox(width: 12),
            Expanded(
              child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
                if (showLabel)
                  Text(t.currentNode,
                      style: PangolinText.caption.copyWith(color: c.fg3, fontWeight: FontWeight.w600, fontSize: 11)),
                Row(children: [
                  Flexible(
                    child: Text(title,
                        overflow: TextOverflow.ellipsis,
                        style: PangolinText.body.copyWith(color: c.fg1, fontWeight: FontWeight.w600)),
                  ),
                  if (smart) ...[const SizedBox(width: 6), Icon(PangolinIcons.zap, size: 13, color: c.accent)],
                ]),
                Text(sub, style: PangolinText.caption.copyWith(color: c.fg3, fontWeight: FontWeight.w400)),
              ]),
            ),
            Icon(PangolinIcons.chevronRight, size: 20, color: c.fg3),
          ]),
        ),
      ),
    );
  }
}

/// 桌面连接页节点胶囊（[zap] 智能选择 · 节点名 · 延迟ms）。
class _NodePill extends StatelessWidget {
  const _NodePill({required this.t, required this.node, required this.smart, required this.pingLabel});
  final AppText t;
  final Node node;
  final bool smart;
  final String pingLabel;

  @override
  Widget build(BuildContext context) {
    final c = context.pangolin;
    final label = smart
        ? '${t.smartSelect} · ${node.localizedName(t.lang)} · $pingLabel'
        : '${node.localizedName(t.lang)} · $pingLabel';
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
      decoration: BoxDecoration(
        color: c.surface,
        border: Border.all(color: c.border),
        borderRadius: BorderRadius.circular(PangolinRadius.full),
      ),
      child: Row(mainAxisSize: MainAxisSize.min, children: [
        if (smart) ...[Icon(PangolinIcons.zap, size: 13, color: c.accent), const SizedBox(width: 7)],
        Text(label,
            style: PangolinText.caption.copyWith(color: c.fg2, fontSize: 12.5, fontWeight: FontWeight.w600)),
      ]),
    );
  }
}
