import 'dart:async';

import 'package:flutter/material.dart';

import '../application/application.dart';
import '../domain/domain.dart';
import 'share_inbox_screen.dart';
import 'theme.dart';

final class ProfileScreen extends StatefulWidget {
  const ProfileScreen({
    required this.authUseCases,
    required this.syncUseCases,
    required this.shareUseCases,
    super.key,
  });

  final AuthUseCases authUseCases;
  final SyncUseCases syncUseCases;
  final ShareUseCases shareUseCases;

  @override
  State<ProfileScreen> createState() => _ProfileScreenState();
}

final class _ProfileScreenState extends State<ProfileScreen> {
  late Future<UserAccountSession?> _session;

  @override
  void initState() {
    super.initState();
    _session = widget.authUseCases.currentSession();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Profil')),
      body: FutureBuilder<UserAccountSession?>(
        future: _session,
        builder: (context, snapshot) {
          if (snapshot.connectionState != ConnectionState.done) {
            return const Center(child: CircularProgressIndicator());
          }
          final session = snapshot.data;
          if (session == null || !session.isLoggedIn) {
            return _SignedOutProfile(
              onRegister: () => _openRegister(context),
              onLogin: () => _openLogin(context),
            );
          }
          return _SignedInProfile(
            session: session,
            syncUseCases: widget.syncUseCases,
            onLogout: () => _confirmLogout(context),
            onShares: () => _openReceivedShares(context),
          );
        },
      ),
    );
  }

  Future<void> _openLogin(BuildContext context) async {
    final connected = await Navigator.of(context).push<bool>(
      MaterialPageRoute(
        builder: (context) => LoginScreen(
          authUseCases: widget.authUseCases,
          syncUseCases: widget.syncUseCases,
          shareUseCases: widget.shareUseCases,
        ),
      ),
    );
    if (connected == true && mounted) {
      _reloadSession();
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Compte connecté. Synchronisation en arrière-plan.'),
        ),
      );
    }
  }

  Future<void> _openRegister(BuildContext context) async {
    final connected = await Navigator.of(context).push<bool>(
      MaterialPageRoute(
        builder: (context) => RegisterScreen(
          authUseCases: widget.authUseCases,
          syncUseCases: widget.syncUseCases,
          shareUseCases: widget.shareUseCases,
        ),
      ),
    );
    if (connected == true && mounted) {
      _reloadSession();
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Compte connecté. Synchronisation en arrière-plan.'),
        ),
      );
    }
  }

  Future<void> _confirmLogout(BuildContext context) async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Se déconnecter ?'),
        content: const Text(
          'Les données restent sur cet appareil. La synchronisation et les '
          'partages seront suspendus jusqu’à une prochaine connexion.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('Annuler'),
          ),
          FilledButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: const Text('Se déconnecter'),
          ),
        ],
      ),
    );
    if (confirmed != true) return;
    await widget.authUseCases.logout();
    if (!mounted) return;
    _reloadSession();
  }

  void _openReceivedShares(BuildContext context) {
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context) =>
            ShareInboxScreen(shareUseCases: widget.shareUseCases),
      ),
    );
  }

  void _reloadSession() {
    setState(() {
      _session = widget.authUseCases.currentSession();
    });
  }
}

final class _SignedOutProfile extends StatelessWidget {
  const _SignedOutProfile({required this.onRegister, required this.onLogin});

  final VoidCallback onRegister;
  final VoidCallback onLogin;

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        CourtBlazerAccentPanel(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Text(
                'Compte optionnel',
                style: Theme.of(context).textTheme.titleLarge,
              ),
              const SizedBox(height: 8),
              const Text(
                'GameTime fonctionne entièrement sans compte. Connecte-toi '
                'seulement si tu veux sauvegarder tes données en ligne ou '
                'partager des programmes et séances.',
              ),
              const SizedBox(height: 16),
              FilledButton(
                onPressed: onRegister,
                child: const Text('Créer un compte'),
              ),
              const SizedBox(height: 8),
              OutlinedButton(
                onPressed: onLogin,
                child: const Text('Se connecter'),
              ),
            ],
          ),
        ),
        const SizedBox(height: 16),
        CourtBlazerAccentPanel(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'Données locales',
                style: Theme.of(context).textTheme.titleMedium,
              ),
              const SizedBox(height: 8),
              const Text(
                'Tes exercices, programmes, séances et historiques sont '
                'enregistrés sur cet appareil.',
              ),
            ],
          ),
        ),
        const SizedBox(height: 16),
        CourtBlazerAccentPanel(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text('Partages', style: Theme.of(context).textTheme.titleMedium),
              const SizedBox(height: 8),
              const Text(
                'Connecte-toi pour envoyer et recevoir des programmes ou des '
                'séances.',
              ),
            ],
          ),
        ),
      ],
    );
  }
}

final class _SignedInProfile extends StatelessWidget {
  const _SignedInProfile({
    required this.session,
    required this.syncUseCases,
    required this.onLogout,
    required this.onShares,
  });

  final UserAccountSession session;
  final SyncUseCases syncUseCases;
  final VoidCallback onLogout;
  final VoidCallback onShares;

  @override
  Widget build(BuildContext context) {
    final displayName = session.displayName?.trim();
    final title = displayName == null || displayName.isEmpty
        ? session.email
        : displayName;
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        CourtBlazerAccentPanel(
          child: Row(
            children: [
              CircleAvatar(radius: 28, child: Text(_profileInitials(title))),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(title, style: Theme.of(context).textTheme.titleLarge),
                    if (title != session.email) ...[
                      const SizedBox(height: 4),
                      Text(session.email),
                    ],
                  ],
                ),
              ),
            ],
          ),
        ),
        const SizedBox(height: 16),
        OutlinedButton.icon(
          onPressed: onLogout,
          icon: const Icon(Icons.logout),
          label: const Text('Se déconnecter'),
        ),
        const SizedBox(height: 16),
        SyncStatusPanel(syncUseCases: syncUseCases),
        const SizedBox(height: 12),
        CourtBlazerAccentPanel(
          child: Material(
            type: MaterialType.transparency,
            child: ListTile(
              contentPadding: EdgeInsets.zero,
              leading: const Icon(Icons.inbox_outlined),
              title: const Text('Partages reçus'),
              subtitle: const Text(
                "Programmes et séances reçus d'autres comptes",
              ),
              trailing: const Icon(Icons.chevron_right),
              onTap: onShares,
            ),
          ),
        ),
      ],
    );
  }
}

final class SyncStatusPanel extends StatefulWidget {
  const SyncStatusPanel({required this.syncUseCases, super.key});

  final SyncUseCases syncUseCases;

  @override
  State<SyncStatusPanel> createState() => _SyncStatusPanelState();
}

final class _SyncStatusPanelState extends State<SyncStatusPanel> {
  late Future<SyncMetadataSnapshot> _status;
  var _syncing = false;

  @override
  void initState() {
    super.initState();
    _status = widget.syncUseCases.currentStatus();
  }

  @override
  Widget build(BuildContext context) {
    return CourtBlazerAccentPanel(
      child: FutureBuilder<SyncMetadataSnapshot>(
        future: _status,
        builder: (context, snapshot) {
          final status = snapshot.data;
          final view = _syncStatusView(status, _syncing);
          return Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Padding(
                    padding: const EdgeInsets.only(top: 2),
                    child: _syncing
                        ? const SizedBox(
                            width: 20,
                            height: 20,
                            child: CircularProgressIndicator(strokeWidth: 2),
                          )
                        : Icon(view.icon),
                  ),
                  const SizedBox(width: 12),
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          'Synchronisation',
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                        const SizedBox(height: 4),
                        Text(view.label),
                      ],
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              OutlinedButton.icon(
                onPressed: _syncing ? null : _syncNow,
                icon: const Icon(Icons.sync),
                label: const Text('Synchroniser maintenant'),
              ),
            ],
          );
        },
      ),
    );
  }

  Future<void> _syncNow() async {
    setState(() {
      _syncing = true;
    });
    await widget.syncUseCases.synchronize(manual: true);
    if (!mounted) return;
    setState(() {
      _syncing = false;
      _status = widget.syncUseCases.currentStatus();
    });
  }
}

final class _SyncStatusView {
  const _SyncStatusView({required this.label, required this.icon});

  final String label;
  final IconData icon;
}

_SyncStatusView _syncStatusView(SyncMetadataSnapshot? metadata, bool syncing) {
  if (syncing || metadata?.status == OnlineSyncStatus.syncing) {
    return const _SyncStatusView(
      label: 'Synchronisation en cours...',
      icon: Icons.sync,
    );
  }
  if (metadata == null) {
    return const _SyncStatusView(
      label: 'Synchronisation en attente',
      icon: Icons.cloud_outlined,
    );
  }
  final lastSuccess = metadata.lastSuccessfulSyncAt;
  if (metadata.status == OnlineSyncStatus.success && lastSuccess != null) {
    return _SyncStatusView(
      label: 'Dernière synchro : ${_relativeSyncTime(lastSuccess)}',
      icon: Icons.cloud_done_outlined,
    );
  }
  if (metadata.status == OnlineSyncStatus.failure) {
    if (lastSuccess != null) {
      return _SyncStatusView(
        label:
            'Dernière synchronisation : ${_relativeSyncTime(lastSuccess)}. '
            'Nouvelle tentative automatique.',
        icon: Icons.schedule,
      );
    }
    return const _SyncStatusView(
      label: 'Synchronisation en attente',
      icon: Icons.schedule,
    );
  }
  return const _SyncStatusView(
    label: 'Synchronisation en attente',
    icon: Icons.cloud_outlined,
  );
}

final class LoginScreen extends StatefulWidget {
  const LoginScreen({
    required this.authUseCases,
    required this.syncUseCases,
    this.shareUseCases,
    super.key,
  });

  final AuthUseCases authUseCases;
  final SyncUseCases syncUseCases;
  final ShareUseCases? shareUseCases;

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

final class _LoginScreenState extends State<LoginScreen> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  String? _error;
  var _submitting = false;

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Se connecter')),
      body: _AuthFormScaffold(
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              TextFormField(
                controller: _emailController,
                decoration: const InputDecoration(labelText: 'Email'),
                keyboardType: TextInputType.emailAddress,
                validator: _emailValidator,
              ),
              const SizedBox(height: 12),
              TextFormField(
                controller: _passwordController,
                decoration: const InputDecoration(labelText: 'Mot de passe'),
                obscureText: true,
                validator: _passwordValidator,
              ),
              if (_error != null) ...[
                const SizedBox(height: 12),
                _InlineAuthError(message: _error!),
              ],
              const SizedBox(height: 16),
              FilledButton(
                onPressed: _submitting ? null : _submit,
                child: Text(_submitting ? 'Connexion...' : 'Se connecter'),
              ),
              const SizedBox(height: 8),
              OutlinedButton(
                onPressed: _submitting
                    ? null
                    : () {
                        Navigator.of(context).pushReplacement(
                          MaterialPageRoute(
                            builder: (context) => RegisterScreen(
                              authUseCases: widget.authUseCases,
                              syncUseCases: widget.syncUseCases,
                              shareUseCases: widget.shareUseCases,
                            ),
                          ),
                        );
                      },
                child: const Text('Créer un compte'),
              ),
              const SizedBox(height: 16),
              Text(
                'Tu peux continuer à utiliser GameTime sans compte.',
                style: Theme.of(context).textTheme.bodySmall,
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _submit() async {
    if (!_formKey.currentState!.validate()) return;
    setState(() {
      _error = null;
      _submitting = true;
    });
    try {
      await widget.authUseCases.login(
        email: _emailController.text,
        password: _passwordController.text,
      );
      unawaited(widget.syncUseCases.synchronize(manual: false));
      final shareUseCases = widget.shareUseCases;
      if (shareUseCases != null) {
        unawaited(shareUseCases.processPendingShareActions());
      }
      if (!mounted) return;
      Navigator.of(context).pop(true);
    } on RemoteAuthException catch (error) {
      if (!mounted) return;
      setState(() {
        _error = _loginErrorMessage(error.failure);
        _submitting = false;
      });
    } on DomainException {
      if (!mounted) return;
      setState(() {
        _error = 'Vérifie les informations saisies.';
        _submitting = false;
      });
    }
  }
}

final class RegisterScreen extends StatefulWidget {
  const RegisterScreen({
    required this.authUseCases,
    required this.syncUseCases,
    this.shareUseCases,
    super.key,
  });

  final AuthUseCases authUseCases;
  final SyncUseCases syncUseCases;
  final ShareUseCases? shareUseCases;

  @override
  State<RegisterScreen> createState() => _RegisterScreenState();
}

final class _RegisterScreenState extends State<RegisterScreen> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _confirmPasswordController = TextEditingController();
  final _displayNameController = TextEditingController();
  String? _error;
  var _submitting = false;

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    _confirmPasswordController.dispose();
    _displayNameController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Créer un compte')),
      body: _AuthFormScaffold(
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              TextFormField(
                controller: _emailController,
                decoration: const InputDecoration(labelText: 'Email'),
                keyboardType: TextInputType.emailAddress,
                validator: _emailValidator,
              ),
              const SizedBox(height: 12),
              TextFormField(
                controller: _passwordController,
                decoration: const InputDecoration(labelText: 'Mot de passe'),
                obscureText: true,
                validator: _newPasswordValidator,
              ),
              const SizedBox(height: 12),
              TextFormField(
                controller: _confirmPasswordController,
                decoration: const InputDecoration(
                  labelText: 'Confirmer le mot de passe',
                ),
                obscureText: true,
                validator: (value) {
                  if (value != _passwordController.text) {
                    return 'Les mots de passe ne correspondent pas.';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 12),
              TextFormField(
                controller: _displayNameController,
                decoration: const InputDecoration(
                  labelText: 'Pseudo (optionnel)',
                ),
              ),
              if (_error != null) ...[
                const SizedBox(height: 12),
                _InlineAuthError(message: _error!),
              ],
              const SizedBox(height: 16),
              FilledButton(
                onPressed: _submitting ? null : _submit,
                child: Text(_submitting ? 'Création...' : 'Créer le compte'),
              ),
              const SizedBox(height: 8),
              OutlinedButton(
                onPressed: _submitting
                    ? null
                    : () {
                        Navigator.of(context).pushReplacement(
                          MaterialPageRoute(
                            builder: (context) => LoginScreen(
                              authUseCases: widget.authUseCases,
                              syncUseCases: widget.syncUseCases,
                              shareUseCases: widget.shareUseCases,
                            ),
                          ),
                        );
                      },
                child: const Text('Déjà un compte ? Se connecter'),
              ),
              const SizedBox(height: 16),
              Text(
                'Le compte sert à synchroniser tes données et partager tes '
                "contenus. L'app reste utilisable sans compte.",
                style: Theme.of(context).textTheme.bodySmall,
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _submit() async {
    if (!_formKey.currentState!.validate()) return;
    setState(() {
      _error = null;
      _submitting = true;
    });
    final displayName = _displayNameController.text.trim();
    try {
      await widget.authUseCases.register(
        email: _emailController.text,
        password: _passwordController.text,
        displayName: displayName.isEmpty ? null : displayName,
      );
      unawaited(widget.syncUseCases.synchronize(manual: false));
      final shareUseCases = widget.shareUseCases;
      if (shareUseCases != null) {
        unawaited(shareUseCases.processPendingShareActions());
      }
      if (!mounted) return;
      Navigator.of(context).pop(true);
    } on RemoteAuthException catch (error) {
      if (!mounted) return;
      setState(() {
        _error = _registerErrorMessage(error.failure);
        _submitting = false;
      });
    } on DomainException {
      if (!mounted) return;
      setState(() {
        _error = 'Vérifie les informations saisies.';
        _submitting = false;
      });
    }
  }
}

final class _AuthFormScaffold extends StatelessWidget {
  const _AuthFormScaffold({required this.child});

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [CourtBlazerAccentPanel(child: child)],
    );
  }
}

final class _InlineAuthError extends StatelessWidget {
  const _InlineAuthError({required this.message});

  final String message;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Text(
      message,
      style: theme.textTheme.bodyMedium?.copyWith(
        color: theme.colorScheme.error,
      ),
    );
  }
}

String? _emailValidator(String? value) {
  final email = value?.trim() ?? '';
  if (!RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$').hasMatch(email)) {
    return 'Saisis une adresse email valide.';
  }
  return null;
}

String? _passwordValidator(String? value) {
  final password = value ?? '';
  if (password.isEmpty) {
    return 'Saisis ton mot de passe.';
  }
  if (password.length < 8) {
    return 'Saisis un mot de passe d’au moins 8 caractères.';
  }
  return null;
}

String? _newPasswordValidator(String? value) {
  if ((value ?? '').length < 8) {
    return 'Saisis un mot de passe d’au moins 8 caractères.';
  }
  return null;
}

String _loginErrorMessage(RemoteAuthFailure failure) {
  return switch (failure) {
    RemoteAuthFailure.invalidCredentials => 'Email ou mot de passe incorrect.',
    RemoteAuthFailure.network =>
      'Connexion impossible pour le moment. Réessaie plus tard.',
    _ => 'Connexion impossible pour le moment. Réessaie plus tard.',
  };
}

String _registerErrorMessage(RemoteAuthFailure failure) {
  return switch (failure) {
    RemoteAuthFailure.emailAlreadyUsed =>
      'Un compte existe déjà avec cet email.',
    RemoteAuthFailure.network =>
      'Création impossible pour le moment. Réessaie plus tard.',
    _ => 'Création impossible pour le moment. Réessaie plus tard.',
  };
}

String _relativeSyncTime(DateTime value) {
  final localValue = value.toLocal();
  final difference = DateTime.now().difference(localValue);
  if (difference.inMinutes < 1) {
    return 'à l’instant';
  }
  if (difference.inHours < 1) {
    return 'il y a ${difference.inMinutes} min';
  }
  if (difference.inDays < 1) {
    return 'il y a ${difference.inHours} h';
  }
  if (difference.inDays == 1) {
    return 'hier à ${_formatHourMinute(localValue)}';
  }
  return 'le ${localValue.day.toString().padLeft(2, '0')}/'
      '${localValue.month.toString().padLeft(2, '0')} '
      'à ${_formatHourMinute(localValue)}';
}

String _formatHourMinute(DateTime value) {
  final hour = value.hour.toString().padLeft(2, '0');
  final minute = value.minute.toString().padLeft(2, '0');
  return '$hour:$minute';
}

String _profileInitials(String value) {
  final trimmed = value.trim();
  if (trimmed.isEmpty) return '?';
  final words = trimmed.split(RegExp(r'\s+'));
  if (words.length == 1) {
    return words.first.substring(0, 1).toUpperCase();
  }
  return '${words.first.substring(0, 1)}${words.last.substring(0, 1)}'
      .toUpperCase();
}
