import 'dart:async';

import 'package:flutter/material.dart';

import '../models/adb_device.dart';
import '../models/install_attempt_result.dart';
import '../models/jenkins_build.dart';
import '../models/pending_install.dart';
import '../services/adb_service.dart';
import '../services/artifact_staging_service.dart';
import 'builds/builds_page.dart';
import 'console/console_page.dart';
import 'devices/devices_page.dart';
import 'settings/settings_page.dart';

export 'builds/builds_page.dart' show JenkinsConnectionStatus;
export 'settings/settings_page.dart'
    show
        JenkinsSessionClearer,
        JenkinsWebLoginLauncher,
        JenkinsWebLoginResult,
        JenkinsTokenSaver;

typedef AdbInstaller =
    Future<AdbInstallResult> Function(AdbDevice device, PendingInstall pending);

class AppSokShell extends StatefulWidget {
  const AppSokShell({
    super.key,
    this.jobLoader,
    this.buildLoader,
    this.artifactDownloader,
    this.artifactStager,
    this.artifactCleaner,
    this.installer,
    this.deviceLoader,
    this.adbDiagnosticsLoader,
    this.webLoginLauncher,
    this.onWebLoginCompleted,
    this.onSessionSaved,
    this.tokenSaver,
    this.sessionClearer,
    this.connectionStatus,
    this.onRetryConnection,
    this.logcatStarter,
  });

  final JenkinsJobLoader? jobLoader;
  final JenkinsBuildLoader? buildLoader;
  final ArtifactDownloader? artifactDownloader;
  final ArtifactStager? artifactStager;
  final ArtifactCleaner? artifactCleaner;
  final AdbInstaller? installer;
  final AdbDeviceLoader? deviceLoader;
  final AdbDiagnosticsLoader? adbDiagnosticsLoader;
  final JenkinsWebLoginLauncher? webLoginLauncher;
  final void Function(JenkinsWebLoginResult result)? onWebLoginCompleted;
  final VoidCallback? onSessionSaved;
  final JenkinsTokenSaver? tokenSaver;
  final JenkinsSessionClearer? sessionClearer;
  final JenkinsConnectionStatus? connectionStatus;
  final VoidCallback? onRetryConnection;
  final AdbLogcatSessionStarter? logcatStarter;

  @override
  State<AppSokShell> createState() => _AppSokShellState();
}

class _AppSokShellState extends State<AppSokShell> {
  int _selectedIndex = 0;
  PendingInstall? _pendingInstall;
  AdbDevice? _selectedConsoleDevice;

  void _handleLogcatRequested(AdbDevice device) {
    setState(() {
      _selectedConsoleDevice = device;
      _selectedIndex = 2;
    });
  }

  // Install lifecycle state — owned by shell so cleanup survives DevicesPage dispose.
  bool _isInstalling = false;
  InstallAttemptResult? _lastInstallAttempt;

  @override
  void dispose() {
    final pending = _pendingInstall;
    if (pending != null) {
      _cleanupPendingInstall(pending);
    }
    super.dispose();
  }

  void _handleInstallRequested(
    JenkinsBuild build,
    BuildArtifact artifact,
    StagedApk? staged,
  ) {
    if (staged == null) return;
    final previous = _pendingInstall;
    setState(() {
      _pendingInstall = PendingInstall(
        apkPath: staged.path,
        fileName: artifact.fileName,
        buildNumber: build.number,
        jobName: build.jobName,
        sizeBytes: staged.sizeBytes,
      );
      _lastInstallAttempt = null;
      _selectedIndex = 1;
    });
    if (previous != null && previous.apkPath != staged.path) {
      _cleanupPendingInstall(previous);
    }
  }

  Future<void> _handleDeviceInstallRequested(
    AdbDevice device,
    PendingInstall pending,
  ) async {
    final installer = widget.installer;
    if (installer == null || _isInstalling) return;

    setState(() {
      _isInstalling = true;
      _lastInstallAttempt = null;
    });

    // Capture pending path before any state mutation.
    final pathToClean = pending.apkPath;

    AdbInstallResult result;
    try {
      result = await installer(device, pending);
    } catch (e) {
      result = AdbInstallResult(exitCode: -1, stdout: '', stderr: e.toString());
    }

    // Cleanup must happen regardless of whether the shell is still mounted.
    _cleanupPath(pathToClean);

    if (!mounted) return;
    setState(() {
      _pendingInstall = null;
      _isInstalling = false;
      _lastInstallAttempt = InstallAttemptResult(
        pendingInstall: pending,
        device: device,
        result: result,
      );
    });
  }

  void _handlePendingInstallCancelled() {
    final pending = _pendingInstall;
    if (pending == null) return;
    setState(() => _pendingInstall = null);
    _cleanupPendingInstall(pending);
  }

  void _handleInstallAttemptCleared() {
    if (_lastInstallAttempt == null) return;
    setState(() => _lastInstallAttempt = null);
  }

  void _cleanupPendingInstall(PendingInstall pending) {
    _cleanupPath(pending.apkPath);
  }

  void _cleanupPath(String path) {
    final cleaner = widget.artifactCleaner;
    if (cleaner != null) {
      unawaited(_runCleanup(cleaner, path));
    }
  }

  Future<void> _runCleanup(ArtifactCleaner cleaner, String path) async {
    try {
      await cleaner(path);
    } catch (_) {
      // Cleanup is best-effort; app teardown and navigation should continue.
    }
  }

  List<_ShellPage> get _pages => [
    _ShellPage(
      label: '빌드',
      icon: Icons.inventory_2_outlined,
      selectedIcon: Icons.inventory_2,
      child: BuildsPage(
        jobLoader: widget.jobLoader,
        buildLoader: widget.buildLoader,
        artifactDownloader: widget.artifactDownloader,
        artifactStager: widget.artifactStager,
        artifactCleaner: widget.artifactCleaner,
        onInstallRequested: _handleInstallRequested,
        connectionStatus: widget.connectionStatus,
        onRetryConnection: widget.onRetryConnection,
      ),
    ),
    _ShellPage(
      label: '디바이스',
      icon: Icons.usb_outlined,
      selectedIcon: Icons.usb,
      child: DevicesPage(
        pendingInstall: _pendingInstall,
        onPendingInstallCancelled: _isInstalling
            ? null
            : _handlePendingInstallCancelled,
        installer: widget.installer == null
            ? null
            : _handleDeviceInstallRequested,
        deviceLoader: widget.deviceLoader,
        isInstalling: _isInstalling,
        lastInstallAttempt: _lastInstallAttempt,
        onInstallAttemptCleared: _handleInstallAttemptCleared,
        onLogcatRequested: _handleLogcatRequested,
      ),
    ),
    _ShellPage(
      label: '콘솔',
      icon: Icons.terminal_outlined,
      selectedIcon: Icons.terminal,
      child: ConsolePage(
        device: _selectedConsoleDevice,
        logcatStarter: widget.logcatStarter,
      ),
    ),
    _ShellPage(
      label: '설정',
      icon: Icons.tune_outlined,
      selectedIcon: Icons.tune,
      child: SettingsPage(
        adbDiagnosticsLoader: widget.adbDiagnosticsLoader,
        webLoginLauncher: widget.webLoginLauncher,
        onWebLoginCompleted: widget.onWebLoginCompleted,
        onSessionSaved: widget.onSessionSaved,
        tokenSaver: widget.tokenSaver,
        sessionClearer: widget.sessionClearer,
      ),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    final page = _pages[_selectedIndex];

    return Scaffold(
      body: SafeArea(
        child: Row(
          children: [
            SizedBox(
              width: 196,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  const _BrandHeader(),
                  Expanded(
                    child: NavigationRail(
                      extended: true,
                      minExtendedWidth: 196,
                      selectedIndex: _selectedIndex,
                      onDestinationSelected: (index) {
                        setState(() => _selectedIndex = index);
                      },
                      destinations: _pages
                          .map(
                            (item) => NavigationRailDestination(
                              icon: Icon(item.icon),
                              selectedIcon: Icon(item.selectedIcon),
                              label: Text(item.label),
                            ),
                          )
                          .toList(),
                    ),
                  ),
                ],
              ),
            ),
            const VerticalDivider(width: 1),
            Expanded(
              child: Column(
                children: [
                  _TopBar(title: page.label),
                  Expanded(child: page.child),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _BrandHeader extends StatelessWidget {
  const _BrandHeader();

  @override
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;

    return Padding(
      padding: const EdgeInsets.fromLTRB(20, 22, 16, 18),
      child: Row(
        children: [
          Container(
            width: 42,
            height: 42,
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: colorScheme.primary,
              borderRadius: BorderRadius.circular(8),
            ),
            child: const Icon(Icons.bolt, color: Colors.white, size: 24),
          ),
          const SizedBox(width: 12),
          const Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'AppSok',
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(fontSize: 22, fontWeight: FontWeight.w900),
                ),
                Text(
                  'Jenkins to USB',
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class _TopBar extends StatelessWidget {
  const _TopBar({required this.title});

  final String title;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 72,
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 28),
        child: Row(
          children: [
            Expanded(
              child: Text(
                title,
                maxLines: 1,
                overflow: TextOverflow.ellipsis,
                style: Theme.of(context).textTheme.titleLarge,
              ),
            ),
            const _StatusPill(
              key: ValueKey('status-jenkins'),
              icon: Icons.key_outlined,
              label: 'Jenkins 대기',
              tooltip: 'Jenkins 상태 연결 대기',
            ),
            const SizedBox(width: 8),
            const _StatusPill(
              key: ValueKey('status-adb'),
              icon: Icons.usb_outlined,
              label: 'ADB 대기',
              tooltip: 'ADB 상태 연결 대기',
            ),
          ],
        ),
      ),
    );
  }
}

class _StatusPill extends StatelessWidget {
  const _StatusPill({
    super.key,
    required this.icon,
    required this.label,
    required this.tooltip,
  });

  final IconData icon;
  final String label;
  final String tooltip;

  @override
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;

    return Container(
      height: 34,
      padding: const EdgeInsets.symmetric(horizontal: 10),
      decoration: BoxDecoration(
        color: Colors.white,
        border: Border.all(color: colorScheme.outlineVariant),
        borderRadius: BorderRadius.circular(8),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Tooltip(
            message: tooltip,
            child: Icon(icon, size: 16, color: colorScheme.onSurfaceVariant),
          ),
          const SizedBox(width: 6),
          Text(
            label,
            style: TextStyle(
              color: colorScheme.onSurfaceVariant,
              fontWeight: FontWeight.w700,
            ),
          ),
        ],
      ),
    );
  }
}

class _ShellPage {
  const _ShellPage({
    required this.label,
    required this.icon,
    required this.selectedIcon,
    required this.child,
  });

  final String label;
  final IconData icon;
  final IconData selectedIcon;
  final Widget child;
}
