import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import '../../../../api/marianumconnect/auth/token_storage.dart';
// Prefixed: the dio endpoint singleton shares its name with the enum from
// dev_tools_settings.dart imported below.
import '../../../../api/marianumconnect/marianumconnect_endpoint.dart'
    as mc_api;
import '../../../../push/push_registration.dart';
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
import '../../../../storage/dev_tools_settings.dart';
import '../../../../storage/settings.dart' as model;
import '../../../../widget/details_bottom_sheet.dart';

/// Bottom-sheet that lets the user switch the active Marianum-Connect
/// endpoint (live / beta / custom). Shared between the dev-tools section and
/// the login screen so both places offer the exact same picker.
///
/// On commit the change lands in the SettingsCubit (which in turn updates
/// the dio singleton via the BlocBuilder in `main.dart`) and the currently
/// stored bearer token is cleared — that token belongs to the old host and
/// would be rejected by the new one.
class MarianumConnectEndpointPicker {
  const MarianumConnectEndpointPicker._();

  static void show(BuildContext context, SettingsCubit settings) {
    showDetailsBottomSheet(
      context,
      header: const ListTile(title: Text('Marianum-Connect-Server')),
      children: (sheetCtx) => [
        BlocBuilder<SettingsCubit, model.Settings>(
          bloc: settings,
          builder: (_, _) {
            final dev = settings.val().devToolsSettings;
            return _PickerBody(
              current: dev.marianumConnectEndpoint,
              customUrl: dev.marianumConnectCustomUrl,
              onChanged: (next, custom) async {
                final mutable = settings.val(write: true).devToolsSettings;
                mutable.marianumConnectEndpoint = next;
                if (custom != null) mutable.marianumConnectCustomUrl = custom;
                await const MarianumConnectTokenStorage().clear();
                // main.dart's BlocBuilder syncs the dio endpoint singleton on
                // its next rebuild, but the push re-registration below must
                // see the new base URL right now — update it here first
                // (idempotent, same value the rebuild would set).
                mc_api.MarianumConnectEndpoint.update(
                  settings
                      .val()
                      .devToolsSettings
                      .resolveMarianumConnectBaseUrl(),
                );
                // A push registration bound to the old proxy would keep
                // routing pushes there; no-op when not registered or the
                // endpoints are unchanged.
                unawaited(PushRegistration().reRegisterIfEndpointChanged());
              },
            );
          },
        ),
      ],
    );
  }

  /// Short human-readable label of the currently selected endpoint — used by
  /// the settings list tile and the login screen hint.
  static String labelFor(DevToolsSettings dev) {
    switch (dev.marianumConnectEndpoint) {
      case MarianumConnectEndpoint.live:
        return 'Normal (${DevToolsSettings.liveUrl})';
      case MarianumConnectEndpoint.beta:
        return 'Beta (${DevToolsSettings.betaUrl})';
      case MarianumConnectEndpoint.custom:
        final url = DevToolsSettings.sanitizeCustomUrl(
          dev.marianumConnectCustomUrl,
        );
        return url == null
            ? 'Eigener Server (ungültig – Normal wird verwendet)'
            : 'Eigener Server ($url)';
    }
  }
}

class _PickerBody extends StatefulWidget {
  final MarianumConnectEndpoint current;
  final String customUrl;
  final Future<void> Function(MarianumConnectEndpoint next, String? customUrl)
  onChanged;

  const _PickerBody({
    required this.current,
    required this.customUrl,
    required this.onChanged,
  });

  @override
  State<_PickerBody> createState() => _PickerBodyState();
}

class _PickerBodyState extends State<_PickerBody> {
  late MarianumConnectEndpoint _selected;
  late TextEditingController _customController;
  String? _customError;

  @override
  void initState() {
    super.initState();
    _selected = widget.current;
    _customController = TextEditingController(text: widget.customUrl);
  }

  @override
  void dispose() {
    _customController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final allowsHttp = DevToolsSettings.allowsHttpCustomEndpoint;
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        RadioGroup<MarianumConnectEndpoint>(
          groupValue: _selected,
          onChanged: _selectEndpoint,
          child: Column(
            children: [
              const RadioListTile<MarianumConnectEndpoint>(
                title: Text('Normal'),
                subtitle: Text(DevToolsSettings.liveUrl),
                value: MarianumConnectEndpoint.live,
              ),
              const RadioListTile<MarianumConnectEndpoint>(
                title: Text('Beta'),
                subtitle: Text(DevToolsSettings.betaUrl),
                value: MarianumConnectEndpoint.beta,
              ),
              RadioListTile<MarianumConnectEndpoint>(
                title: const Text('Eigener Server'),
                subtitle: Text(
                  allowsHttp
                      ? 'HTTP oder HTTPS, ohne abschließenden Slash. '
                            'HTTP nur für lokale Entwicklung.'
                      : 'Nur HTTPS-URLs, ohne abschließenden Slash.',
                ),
                value: MarianumConnectEndpoint.custom,
              ),
            ],
          ),
        ),
        if (_selected == MarianumConnectEndpoint.custom)
          Padding(
            padding: const EdgeInsets.fromLTRB(24, 0, 24, 16),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                TextField(
                  controller: _customController,
                  keyboardType: TextInputType.url,
                  decoration: InputDecoration(
                    labelText: allowsHttp ? 'http(s)://...' : 'https://...',
                    errorText: _customError,
                  ),
                  onChanged: (_) => setState(() => _customError = null),
                ),
                if (allowsHttp && _isHttpUrl(_customController.text))
                  const Padding(
                    padding: EdgeInsets.only(top: 8),
                    child: Text(
                      '⚠ HTTP überträgt den Bearer-Token unverschlüsselt. '
                      'Nur für lokale Entwicklung benutzen.',
                      style: TextStyle(fontSize: 12, color: Colors.orange),
                    ),
                  ),
              ],
            ),
          ),
        Padding(
          padding: const EdgeInsets.all(16),
          child: FilledButton(
            onPressed: _confirm,
            child: const Text('Übernehmen'),
          ),
        ),
      ],
    );
  }

  void _selectEndpoint(MarianumConnectEndpoint? value) {
    if (value == null) return;
    setState(() {
      _selected = value;
      _customError = null;
    });
  }

  Future<void> _confirm() async {
    if (_selected == MarianumConnectEndpoint.custom) {
      final sanitized = DevToolsSettings.sanitizeCustomUrl(
        _customController.text,
      );
      if (sanitized == null) {
        setState(
          () => _customError = DevToolsSettings.allowsHttpCustomEndpoint
              ? 'Ungültige URL (http(s)://host[:port])'
              : 'Ungültige URL — nur HTTPS erlaubt',
        );
        return;
      }
      await widget.onChanged(_selected, sanitized);
    } else {
      await widget.onChanged(_selected, null);
    }
    if (!mounted) return;
    Navigator.of(context).pop();
  }

  static bool _isHttpUrl(String value) {
    final trimmed = value.trim();
    final uri = Uri.tryParse(trimmed);
    return uri != null && uri.hasScheme && uri.scheme == 'http';
  }
}
