import "package:flutter/material.dart";

import "../config.dart";
import "../i18n.dart";
import "../main.dart";
import "../servers.dart";
import "../theme.dart";

/// The server picker and the add/edit/sign-in sheet behind it — the phone's
/// half of the web app's rail server switcher.
///
/// The picker names the server you are reading right now, which matters most
/// when two of them hold different cars and the screens otherwise look
/// identical, and switches between them in one tap once each has been signed
/// into.

/// Opens the picker. With only one server known there is nothing to pick
/// between, so it goes straight to adding the second one.
Future<void> showServerPicker(BuildContext context) {
  if (serverRegistry.list.length < 2) return showServerEditor(context);
  return showModalBottomSheet<void>(
    context: context,
    isScrollControlled: true,
    builder: (_) => const _ServerPickerSheet(),
  );
}

/// Add a server, edit one, or sign into it — one sheet, because for a server you
/// have just typed in they are the same act: an address is only worth keeping
/// once something has answered at it.
Future<void> showServerEditor(BuildContext context, {ServerEntry? server}) {
  return showModalBottomSheet<void>(
    context: context,
    isScrollControlled: true,
    builder: (_) => _ServerEditorSheet(server: server),
  );
}

/// Each server carries its own profile, so the appearance prefs come from
/// whichever one is now active. Failures are ignored: the screens behind this
/// sheet report their own load errors.
void adoptActiveServerProfile() {
  apiClient.getMe().then((profile) {
    appSettings.applyFromProfile(profile);
    authService.adoptRole(profile);
  }).catchError((_) {});
}

class _ServerPickerSheet extends StatefulWidget {
  const _ServerPickerSheet();
  @override
  State<_ServerPickerSheet> createState() => _ServerPickerSheetState();
}

class _ServerPickerSheetState extends State<_ServerPickerSheet> {
  Future<void> _choose(ServerEntry server) async {
    if (serverRegistry.isConnected(server.id)) {
      serverRegistry.setActive(server.id);
      adoptActiveServerProfile();
      Navigator.pop(context);
      return;
    }
    // No session for it yet — the same sheet that adds a server signs you in.
    await showServerEditor(context, server: server);
    if (mounted) setState(() {});
  }

  Future<void> _edit(ServerEntry server) async {
    await showServerEditor(context, server: server);
    if (mounted) setState(() {});
  }

  Future<void> _add() async {
    await showServerEditor(context);
    if (mounted) setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    final muted = DriverVault.muted(context);
    return Padding(
      padding: EdgeInsets.only(
        left: 16,
        right: 16,
        top: 16,
        bottom: DriverVault.sheetBottomInset(context),
      ),
      child: SingleChildScrollView(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(t("servers.title"),
                style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600)),
            Padding(
              padding: const EdgeInsets.only(top: 2, bottom: 8),
              child: Text(t("servers.switchHint"),
                  style: TextStyle(fontSize: 12, color: muted)),
            ),
            for (final server in serverRegistry.list)
              ListTile(
                contentPadding: EdgeInsets.zero,
                // Green once this server has a session of its own; muted means
                // picking it will ask for credentials rather than switch.
                leading: Tooltip(
                  message: serverRegistry.isConnected(server.id)
                      ? t("servers.connected")
                      : t("servers.notConnected"),
                  child: Icon(Icons.circle,
                      size: 10,
                      color: serverRegistry.isConnected(server.id)
                          ? DriverVault.success
                          : muted.withValues(alpha: 0.4)),
                ),
                title: Text(serverRegistry.displayName(server),
                    style: const TextStyle(fontWeight: FontWeight.w600)),
                subtitle: Text(serverRegistry.baseFor(server),
                    style: DriverVault.mono(context, size: 11, color: muted),
                    overflow: TextOverflow.ellipsis),
                trailing: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    if (server.id == serverRegistry.activeId)
                      Icon(Icons.check, size: 18, color: Theme.of(context).colorScheme.primary),
                    IconButton(
                      icon: const Icon(Icons.edit_outlined, size: 18),
                      tooltip: t("common.edit"),
                      onPressed: () => _edit(server),
                    ),
                  ],
                ),
                onTap: () => _choose(server),
              ),
            const Divider(),
            TextButton.icon(
              onPressed: _add,
              icon: const Icon(Icons.add),
              label: Text(t("servers.add")),
            ),
          ],
        ),
      ),
    );
  }
}

class _ServerEditorSheet extends StatefulWidget {
  // An existing server to edit/connect to, or null to add a new one.
  final ServerEntry? server;
  const _ServerEditorSheet({this.server});
  @override
  State<_ServerEditorSheet> createState() => _ServerEditorSheetState();
}

class _ServerEditorSheetState extends State<_ServerEditorSheet> {
  late final TextEditingController _name;
  late final TextEditingController _url;
  final _email = TextEditingController();
  final _password = TextEditingController();
  bool _showPassword = false;
  bool _busy = false;
  String? _error;

  bool get _isNew => widget.server == null;
  bool get _isHome => widget.server?.isHome == true;
  bool get _connected =>
      widget.server != null && serverRegistry.isConnected(widget.server!.id);

  @override
  void initState() {
    super.initState();
    _name = TextEditingController(text: widget.server?.name ?? "");
    _url = TextEditingController(text: widget.server?.url ?? "");
  }

  @override
  void dispose() {
    _name.dispose();
    _url.dispose();
    _email.dispose();
    _password.dispose();
    super.dispose();
  }

  Future<void> _submit() async {
    setState(() {
      _busy = true;
      _error = null;
    });
    // Keep the server added in this attempt, so a second try after a bad
    // password edits that entry instead of stacking up duplicates.
    var target = widget.server;
    // Read before the save: moving a connected server to a new address drops
    // the token minted by the old one, and that is a save, not a sign-in — the
    // credentials to replace it were never asked for.
    final wasConnected = _connected;
    try {
      if (target == null) {
        target = serverRegistry.add(name: _name.text, url: _url.text);
      } else {
        serverRegistry.update(target.id, name: _name.text, url: _url.text);
      }
      if (!wasConnected) {
        await authService.connect(target.id, _email.text.trim(), _password.text);
        adoptActiveServerProfile();
      }
      if (mounted) Navigator.pop(context);
    } catch (e) {
      // A server that never answered is not worth keeping in the list.
      if (_isNew && target != null) serverRegistry.remove(target.id);
      if (mounted) setState(() => _error = e.toString());
    } finally {
      if (mounted) setState(() => _busy = false);
    }
  }

  void _signOut() {
    authService.disconnect(widget.server!.id);
    Navigator.pop(context);
  }

  Future<void> _remove() async {
    final name = serverRegistry.displayName(widget.server);
    final ok = await showDialog<bool>(
      context: context,
      builder: (ctx) => AlertDialog(
        content: Text(t("servers.removeConfirm", params: {"name": name})),
        actions: [
          TextButton(onPressed: () => Navigator.pop(ctx, false), child: Text(t("common.cancel"))),
          FilledButton(onPressed: () => Navigator.pop(ctx, true), child: Text(t("common.remove"))),
        ],
      ),
    );
    if (ok != true || !mounted) return;
    serverRegistry.remove(widget.server!.id);
    if (mounted) Navigator.pop(context);
  }

  @override
  Widget build(BuildContext context) {
    final muted = DriverVault.muted(context);
    return Padding(
      padding: EdgeInsets.only(
        left: 16,
        right: 16,
        top: 16,
        bottom: DriverVault.sheetBottomInset(context),
      ),
      child: SingleChildScrollView(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(_isNew ? t("servers.addTitle") : serverRegistry.displayName(widget.server),
                style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600)),
            const SizedBox(height: 12),
            if (_error != null)
              Padding(
                padding: const EdgeInsets.only(bottom: 8),
                child: Text(_error!, style: const TextStyle(color: DriverVault.danger)),
              ),
            TextField(
              controller: _name,
              textCapitalization: TextCapitalization.words,
              decoration: InputDecoration(
                labelText: t("servers.name"),
                hintText: t("servers.namePlaceholder"),
                border: const OutlineInputBorder(),
                isDense: true,
              ),
            ),
            const SizedBox(height: 10),
            TextField(
              controller: _url,
              keyboardType: TextInputType.url,
              autocorrect: false,
              decoration: InputDecoration(
                labelText: t("servers.url"),
                hintText: _isHome ? kDefaultApiBase : "https://garage.example.com",
                border: const OutlineInputBorder(),
                isDense: true,
                helperText: _isHome ? t("servers.urlHomeHint") : t("servers.urlHint"),
                helperMaxLines: 3,
              ),
            ),
            // Credentials only while this server has no session: each server is
            // its own PocketBase, so signing in happens once per server.
            if (!_connected) ...[
              const SizedBox(height: 14),
              const Divider(height: 1),
              const SizedBox(height: 14),
              TextField(
                controller: _email,
                keyboardType: TextInputType.emailAddress,
                autocorrect: false,
                decoration: InputDecoration(
                  labelText: t("login.email"),
                  border: const OutlineInputBorder(),
                  isDense: true,
                ),
              ),
              const SizedBox(height: 10),
              TextField(
                controller: _password,
                obscureText: !_showPassword,
                decoration: InputDecoration(
                  labelText: t("login.password"),
                  border: const OutlineInputBorder(),
                  isDense: true,
                  suffixIcon: IconButton(
                    icon: Icon(_showPassword ? Icons.visibility_off : Icons.visibility),
                    tooltip: _showPassword ? t("login.hidePassword") : t("login.showPassword"),
                    onPressed: () => setState(() => _showPassword = !_showPassword),
                  ),
                ),
                onSubmitted: (_) => _submit(),
              ),
            ],
            const SizedBox(height: 14),
            SizedBox(
              width: double.infinity,
              child: FilledButton(
                onPressed: _busy ? null : _submit,
                child: Text(_busy
                    ? t("servers.connecting")
                    : _connected
                        ? t("common.save")
                        : t("servers.connect")),
              ),
            ),
            if (_connected || (!_isNew && !_isHome))
              Padding(
                padding: const EdgeInsets.only(top: 4),
                child: Row(
                  children: [
                    if (_connected)
                      TextButton(
                        onPressed: _signOut,
                        style: TextButton.styleFrom(foregroundColor: muted),
                        child: Text(t("servers.signOut")),
                      ),
                    const Spacer(),
                    if (!_isNew && !_isHome)
                      TextButton(
                        onPressed: _remove,
                        style: TextButton.styleFrom(foregroundColor: DriverVault.danger),
                        child: Text(t("common.remove")),
                      ),
                  ],
                ),
              ),
          ],
        ),
      ),
    );
  }
}
