import 'package:flutter/material.dart';

import 'features/app_shell.dart';
import 'features/devices/devices_page.dart';
import 'services/adb_service.dart';
import 'services/artifact_staging_service.dart';
import 'services/jenkins_artifact_session.dart';
import 'services/jenkins_client.dart';
import 'services/token_store.dart';
import 'theme/app_theme.dart';

class AppSokApp extends StatefulWidget {
  const AppSokApp({
    super.key,
    this.tokenStore,
    this.jenkinsClient,
    this.artifactStagingService,
    this.session,
    this.adbDeviceLoader,
    this.adbInstaller,
    this.adbDiagnosticsLoader,
    this.webLoginLauncher,
    this.onWebLoginCompleted,
    this.adbLogcatStarter,
  });

  final TokenStore? tokenStore;
  final JenkinsClient? jenkinsClient;
  final ArtifactStagingService? artifactStagingService;
  final JenkinsArtifactSession? session;
  final AdbDeviceLoader? adbDeviceLoader;
  final AdbInstaller? adbInstaller;
  final AdbDiagnosticsLoader? adbDiagnosticsLoader;
  final JenkinsWebLoginLauncher? webLoginLauncher;
  final void Function(JenkinsWebLoginResult result)? onWebLoginCompleted;
  final AdbLogcatSessionStarter? adbLogcatStarter;

  @override
  State<AppSokApp> createState() => _AppSokAppState();
}

class _AppSokAppState extends State<AppSokApp> {
  late final JenkinsArtifactSession _session =
      widget.session ??
      JenkinsArtifactSession(
        store: widget.tokenStore ?? TokenStore(),
        client: widget.jenkinsClient ?? JenkinsClient(),
        stager: widget.artifactStagingService ?? ArtifactStagingService(),
      );

  late final AdbService _adbService = AdbService();

  // Mutable so that _onSessionSaved and _retryRestore can trigger re-restore.
  late Future<JenkinsSessionRestoreResult> _startup =
      _session.restoreDetailed();

  void _onSessionSaved() {
    if (!mounted) return;
    setState(() {
      _startup = _session.restoreDetailed();
    });
  }

  Future<void> _clearSession() async {
    await _session.clear();
    if (!mounted) return;
    setState(() {
      _startup = Future.value(
        const JenkinsSessionRestoreResult(
          kind: JenkinsSessionRestoreKind.missing,
        ),
      );
    });
  }

  void _retryRestore() {
    if (!mounted) return;
    setState(() {
      _startup = _session.restoreDetailed();
    });
  }

  Future<bool> _saveToken(
    String baseUrl,
    String username,
    String apiToken,
  ) async {
    final store = _session.store;
    final baseUri = Uri.tryParse(baseUrl);
    if (baseUri == null ||
        (baseUri.scheme != 'http' && baseUri.scheme != 'https')) {
      return false;
    }
    try {
      await store.saveSession(
        JenkinsSessionConfig(
          baseUrl: baseUri,
          credentials: JenkinsCredentials(
            username: username,
            apiToken: apiToken,
          ),
        ),
      );
      final result = await _session.restoreDetailed();
      if (!result.isRestored) {
        await store.clearSession();
        return false;
      }
      return true;
    } catch (_) {
      await store.clearSession();
      return false;
    }
  }

  JenkinsConnectionStatus? _connectionStatus(JenkinsSessionRestoreResult r) {
    if (r.isRestored) return null;
    return switch (r.kind) {
      JenkinsSessionRestoreKind.reauthRequired =>
        JenkinsConnectionStatus.reauthRequired,
      JenkinsSessionRestoreKind.networkFailure =>
        JenkinsConnectionStatus.networkFailure,
      JenkinsSessionRestoreKind.serverFailure =>
        JenkinsConnectionStatus.serverFailure,
      JenkinsSessionRestoreKind.missing || JenkinsSessionRestoreKind.restored =>
        JenkinsConnectionStatus.missing,
    };
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<JenkinsSessionRestoreResult>(
      future: _startup,
      builder: (context, snapshot) {
        final result = snapshot.data;
        final isReady = result?.isRestored ?? false;
        final connStatus = result != null ? _connectionStatus(result) : null;
        final canRetry =
            connStatus == JenkinsConnectionStatus.networkFailure ||
            connStatus == JenkinsConnectionStatus.serverFailure;

        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'AppSok',
          theme: AppTheme.light(),
          home: AppSokShell(
            jobLoader: isReady ? _session.loadJobs : null,
            buildLoader: isReady ? _session.loadBuilds : null,
            artifactDownloader: isReady ? _session.downloadArtifact : null,
            artifactStager: isReady ? _session.stageApk : null,
            artifactCleaner: isReady ? _session.cleanup : null,
            deviceLoader: widget.adbDeviceLoader ?? _adbService.listDevices,
            installer:
                widget.adbInstaller ??
                (device, pending) => _adbService.installApk(
                  serial: device.serial,
                  apkPath: pending.apkPath,
                ),
            adbDiagnosticsLoader:
                widget.adbDiagnosticsLoader ?? _adbService.collectDiagnostics,
            logcatStarter: widget.adbLogcatStarter ?? _adbService.startLogcat,
            webLoginLauncher: widget.webLoginLauncher,
            onWebLoginCompleted: widget.onWebLoginCompleted,
            onSessionSaved: _onSessionSaved,
            tokenSaver: _saveToken,
            sessionClearer: _clearSession,
            connectionStatus: connStatus,
            onRetryConnection: canRetry ? _retryRestore : null,
          ),
        );
      },
    );
  }
}
