import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/core/models/discovery_result.dart';
import 'package:sharedinbox/core/utils/host_utils.dart';
import 'package:sharedinbox/core/utils/logger.dart';
import 'package:sharedinbox/di.dart';
import 'package:sharedinbox/ui/widgets/try_connection_button.dart';

enum _Step { email, detecting, chooseType, jmapForm, imapForm, connecting }

class AddAccountScreen extends ConsumerStatefulWidget {
  const AddAccountScreen({super.key});

  @override
  ConsumerState<AddAccountScreen> createState() => _AddAccountScreenState();
}

class _AddAccountScreenState extends ConsumerState<AddAccountScreen> {
  var _step = _Step.email;
  String? _errorMessage;

  // -- controllers -----------------------------------------------------------
  final _emailCtrl = TextEditingController();
  final _displayNameCtrl = TextEditingController();
  final _usernameCtrl = TextEditingController();
  final _passwordCtrl = TextEditingController();
  final _jmapApiUrlCtrl = TextEditingController();
  final _imapHostCtrl = TextEditingController();
  final _imapPortCtrl = TextEditingController(text: '993');
  final _smtpHostCtrl = TextEditingController();
  final _smtpPortCtrl = TextEditingController(text: '465');
  var _imapSsl = true;
  var _smtpSsl = true;

  // -- "Try connection" state ------------------------------------------------
  bool _tryTesting = false;
  String? _tryOk;
  String? _tryErr;

  // -- form keys -------------------------------------------------------------
  final _emailFormKey = GlobalKey<FormState>();
  final _jmapFormKey = GlobalKey<FormState>();
  final _imapFormKey = GlobalKey<FormState>();

  @override
  void initState() {
    super.initState();
    _imapHostCtrl.addListener(_rebuild);
    _smtpHostCtrl.addListener(_rebuild);
  }

  void _rebuild() => setState(() {});

  @override
  void dispose() {
    _imapHostCtrl.removeListener(_rebuild);
    _smtpHostCtrl.removeListener(_rebuild);
    for (final c in [
      _emailCtrl,
      _displayNameCtrl,
      _usernameCtrl,
      _passwordCtrl,
      _jmapApiUrlCtrl,
      _imapHostCtrl,
      _imapPortCtrl,
      _smtpHostCtrl,
      _smtpPortCtrl,
    ]) {
      c.dispose();
    }
    super.dispose();
  }

  // -- actions ---------------------------------------------------------------

  Future<void> _detectAccount() async {
    if (!_emailFormKey.currentState!.validate()) return;
    setState(() {
      _step = _Step.detecting;
      _errorMessage = null;
    });
    try {
      final result = await ref
          .read(accountDiscoveryServiceProvider)
          .discover(_emailCtrl.text.trim());
      if (!mounted) return;
      switch (result) {
        case JmapDiscovery(:final sessionUrl):
          _jmapApiUrlCtrl.text = sessionUrl;
          setState(() => _step = _Step.jmapForm);
        case ImapSmtpDiscovery(
            :final imapHost,
            :final imapPort,
            :final smtpHost,
            :final smtpPort,
            :final smtpSsl,
          ):
          _imapHostCtrl.text = imapHost;
          _imapPortCtrl.text = imapPort.toString();
          _smtpHostCtrl.text = smtpHost;
          _smtpPortCtrl.text = smtpPort.toString();
          _smtpSsl = smtpSsl;
          setState(() => _step = _Step.imapForm);
        case UnknownDiscovery():
          setState(() => _step = _Step.chooseType);
      }
    } catch (e) {
      log('Account discovery failed: $e');
      if (mounted) setState(() => _step = _Step.chooseType);
    }
  }

  Account _buildJmapAccount() => Account(
        id: DateTime.now().millisecondsSinceEpoch.toString(),
        displayName: _displayNameCtrl.text.trim(),
        email: _emailCtrl.text.trim(),
        username: _usernameCtrl.text.trim(),
        type: AccountType.jmap,
        jmapUrl: _jmapApiUrlCtrl.text.trim(),
      );

  Account _buildImapAccount() {
    final imapHost = _imapHostCtrl.text.trim();
    final smtpHost = _smtpHostCtrl.text.trim();
    return Account(
      id: DateTime.now().millisecondsSinceEpoch.toString(),
      displayName: _displayNameCtrl.text.trim(),
      email: _emailCtrl.text.trim(),
      username: _usernameCtrl.text.trim(),
      imapHost: imapHost,
      imapPort: int.parse(_imapPortCtrl.text),
      imapSsl: isLocalhost(imapHost) ? _imapSsl : true,
      smtpHost: smtpHost,
      smtpPort: int.parse(_smtpPortCtrl.text),
      smtpSsl: isLocalhost(smtpHost) ? _smtpSsl : true,
    );
  }

  Future<void> _tryConnection(
    GlobalKey<FormState> formKey,
    Account Function() buildAccount,
  ) async {
    if (!formKey.currentState!.validate()) return;
    setState(() {
      _tryTesting = true;
      _tryOk = null;
      _tryErr = null;
    });
    try {
      final account = buildAccount();
      final effective = await ref
          .read(connectionTestServiceProvider)
          .testConnection(account, _passwordCtrl.text);
      if (mounted) {
        setState(() {
          _tryTesting = false;
          _tryOk = 'Connected as $effective';
        });
      }
    } catch (e) {
      if (mounted) {
        setState(() {
          _tryTesting = false;
          _tryErr = e.toString();
        });
      }
    }
  }

  Future<void> _saveJmap() async {
    if (!_jmapFormKey.currentState!.validate()) return;
    setState(() {
      _step = _Step.connecting;
      _errorMessage = null;
    });
    try {
      final account = _buildJmapAccount();
      final effective = await ref
          .read(connectionTestServiceProvider)
          .testConnection(account, _passwordCtrl.text);
      final accountToSave = Account(
        id: account.id,
        displayName: account.displayName,
        email: account.email,
        username: account.username.isNotEmpty ? account.username : effective,
        type: account.type,
        jmapUrl: account.jmapUrl,
      );
      await ref
          .read(accountRepositoryProvider)
          .addAccount(accountToSave, _passwordCtrl.text);
      if (mounted) context.pop();
    } catch (e) {
      if (mounted) {
        setState(() {
          _step = _Step.jmapForm;
          _errorMessage = 'Connection failed: $e';
        });
      }
    }
  }

  Future<void> _saveImap() async {
    if (!_imapFormKey.currentState!.validate()) return;
    setState(() {
      _step = _Step.connecting;
      _errorMessage = null;
    });
    try {
      final account = _buildImapAccount();
      final effective = await ref
          .read(connectionTestServiceProvider)
          .testConnection(account, _passwordCtrl.text);
      final accountToSave = Account(
        id: account.id,
        displayName: account.displayName,
        email: account.email,
        username: account.username.isNotEmpty ? account.username : effective,
        imapHost: account.imapHost,
        imapPort: account.imapPort,
        smtpHost: account.smtpHost,
        smtpPort: account.smtpPort,
        smtpSsl: account.smtpSsl,
        manageSieveHost: account.manageSieveHost,
        manageSievePort: account.manageSievePort,
        manageSieveSsl: account.manageSieveSsl,
      );
      await ref
          .read(accountRepositoryProvider)
          .addAccount(accountToSave, _passwordCtrl.text);
      // Probe ManageSieve in the background; the menu starts visible (null)
      // and disappears on probe failure via the observeAccounts stream.
      unawaited(ref.read(manageSieveProbeServiceProvider).probe(accountToSave));
      if (mounted) context.pop();
    } catch (e) {
      if (mounted) {
        setState(() {
          _step = _Step.imapForm;
          _errorMessage = 'Connection failed: $e';
        });
      }
    }
  }

  // -- build -----------------------------------------------------------------

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Add account')),
      body: switch (_step) {
        _Step.email => _buildEmailStep(),
        _Step.detecting => _buildSpinner('Detecting account settings\u2026'),
        _Step.chooseType => _buildChooseTypeStep(),
        _Step.jmapForm => _buildJmapForm(),
        _Step.imapForm => _buildImapForm(),
        _Step.connecting => _buildSpinner('Connecting\u2026'),
      },
    );
  }

  // -- step widgets ----------------------------------------------------------

  Widget _buildEmailStep() {
    return Padding(
      padding: const EdgeInsets.all(16),
      child: Form(
        key: _emailFormKey,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          mainAxisSize: MainAxisSize.min,
          children: [
            TextFormField(
              key: const Key('emailField'),
              controller: _emailCtrl,
              keyboardType: TextInputType.emailAddress,
              autofocus: true,
              decoration: const InputDecoration(
                labelText: 'Email address',
                border: OutlineInputBorder(),
              ),
              validator: (v) {
                if (v == null || v.trim().isEmpty) return 'Required';
                if (!v.contains('@')) return 'Enter a valid email address';
                return null;
              },
            ),
            const SizedBox(height: 16),
            FilledButton(
              onPressed: _detectAccount,
              child: const Text('Continue'),
            ),
            const SizedBox(height: 8),
            OutlinedButton.icon(
              key: const Key('importAccountButton'),
              icon: const Icon(Icons.qr_code_scanner),
              label: const Text('Receive account'),
              onPressed: () => context.push('/accounts/receive'),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildSpinner(String label) {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          const CircularProgressIndicator(),
          const SizedBox(height: 16),
          Text(label),
        ],
      ),
    );
  }

  Widget _buildChooseTypeStep() {
    return Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(
            'Could not auto-detect settings for '
            '${_emailCtrl.text.trim()}.\n'
            'Choose account type:',
          ),
          const SizedBox(height: 24),
          FilledButton(
            onPressed: () => setState(() {
              _jmapApiUrlCtrl.clear();
              _step = _Step.jmapForm;
            }),
            child: const Text('JMAP'),
          ),
          const SizedBox(height: 12),
          OutlinedButton(
            onPressed: () => setState(() {
              _imapHostCtrl.clear();
              _imapPortCtrl.text = '993';
              _imapSsl = true;
              _smtpHostCtrl.clear();
              _smtpPortCtrl.text = '465';
              _smtpSsl = true;
              _step = _Step.imapForm;
            }),
            child: const Text('IMAP / SMTP'),
          ),
        ],
      ),
    );
  }

  Widget _buildJmapForm() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Form(
        key: _jmapFormKey,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            _emailHeader('JMAP'),
            if (_errorMessage != null) _errorBanner(),
            _field(_displayNameCtrl, 'Display name'),
            _field(
              _jmapApiUrlCtrl,
              'JMAP API URL',
              keyboardType: TextInputType.url,
            ),
            _field(
              _usernameCtrl,
              'Username (leave blank to use email)',
              required: false,
            ),
            _field(_passwordCtrl, 'Password', obscure: true),
            TryConnectionButton(
              buttonKey: const Key('tryConnectionButton'),
              testing: _tryTesting,
              okMessage: _tryOk,
              errorMessage: _tryErr,
              onPressed: () => _tryConnection(_jmapFormKey, _buildJmapAccount),
            ),
            const SizedBox(height: 8),
            FilledButton(onPressed: _saveJmap, child: const Text('Save')),
          ],
        ),
      ),
    );
  }

  Widget _buildImapForm() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Form(
        key: _imapFormKey,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            _emailHeader('IMAP / SMTP'),
            if (_errorMessage != null) _errorBanner(),
            _field(_displayNameCtrl, 'Display name'),
            _field(
              _usernameCtrl,
              'Username (leave blank to use email)',
              required: false,
            ),
            _field(_passwordCtrl, 'Password', obscure: true),
            const Divider(height: 32),
            Text('IMAP', style: Theme.of(context).textTheme.titleSmall),
            _field(_imapHostCtrl, 'Host', validator: validateHostname),
            _field(_imapPortCtrl, 'Port', keyboardType: TextInputType.number),
            if (isLocalhost(_imapHostCtrl.text.trim()))
              SwitchListTile(
                title: const Text('SSL/TLS'),
                value: _imapSsl,
                onChanged: (v) => setState(() => _imapSsl = v),
              ),
            const Divider(height: 32),
            Text('SMTP', style: Theme.of(context).textTheme.titleSmall),
            _field(_smtpHostCtrl, 'Host', validator: validateHostname),
            _field(_smtpPortCtrl, 'Port', keyboardType: TextInputType.number),
            if (isLocalhost(_smtpHostCtrl.text.trim()))
              SwitchListTile(
                title: const Text('SSL/TLS'),
                value: _smtpSsl,
                onChanged: (v) => setState(() => _smtpSsl = v),
              ),
            TryConnectionButton(
              buttonKey: const Key('tryConnectionButton'),
              testing: _tryTesting,
              okMessage: _tryOk,
              errorMessage: _tryErr,
              onPressed: () => _tryConnection(_imapFormKey, _buildImapAccount),
            ),
            const SizedBox(height: 8),
            FilledButton(onPressed: _saveImap, child: const Text('Save')),
          ],
        ),
      ),
    );
  }

  // -- small helpers ---------------------------------------------------------

  Widget _emailHeader(String accountTypeLabel) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            _emailCtrl.text.trim(),
            style: Theme.of(context).textTheme.titleMedium,
          ),
          Text(accountTypeLabel, style: Theme.of(context).textTheme.bodySmall),
        ],
      ),
    );
  }

  Widget _errorBanner() {
    return Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: Text(
        _errorMessage!,
        style: TextStyle(color: Theme.of(context).colorScheme.error),
      ),
    );
  }

  Widget _field(
    TextEditingController ctrl,
    String label, {
    bool obscure = false,
    bool required = true,
    TextInputType? keyboardType,
    String? Function(String?)? validator,
  }) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 6),
      child: TextFormField(
        controller: ctrl,
        obscureText: obscure,
        keyboardType: keyboardType,
        decoration: InputDecoration(
          labelText: label,
          border: const OutlineInputBorder(),
        ),
        validator: validator ??
            (required
                ? (v) => (v == null || v.trim().isEmpty) ? 'Required' : null
                : null),
      ),
    );
  }
}
