import 'package:flutter/material.dart';

import 'package:flutter_settings_ui/flutter_settings_ui.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
import 'package:pweb/utils/error/snackbar.dart';

enum _EditState { view, edit, saving }

/// Базовый класс, управляющий состояниями (view/edit/saving),
/// показом snackbar ошибок и успешного сохранения.
abstract class BaseEditTile<T> extends AbstractSettingsTile {
  const BaseEditTile({
    super.key,
    required this.icon,
    required this.title,
    required this.valueGetter,
    required this.valueSetter,
    required this.errorSituation,
  });

  final IconData icon;
  final String title;
  final ValueGetter<T?> valueGetter;
  final Future<void> Function(T) valueSetter;
  final String errorSituation;

  /// Рисует в режиме просмотра (read-only).
  Widget buildView(BuildContext context, T? value);

  /// Рисует UI редактора.
  /// Если [useDialogEditor]==true, его обернут в диалог.
  Widget buildEditor(
    BuildContext context,
    T? initial,
    void Function(T) onSave,
    VoidCallback onCancel,
    bool isSaving,
  );

  /// true → показывать редактор в диалоге, false → inline под заголовком.
  bool get useDialogEditor => false;

  @override
  Widget build(BuildContext context) => _BaseEditTileBody<T>(delegate: this);
}

class _BaseEditTileBody<T> extends StatefulWidget {
  const _BaseEditTileBody({required this.delegate});
  final BaseEditTile<T> delegate;
  @override
  State<_BaseEditTileBody<T>> createState() => _BaseEditTileBodyState<T>();
}

class _BaseEditTileBodyState<T> extends State<_BaseEditTileBody<T>> {
  _EditState _state = _EditState.view;
  bool get _isSaving => _state == _EditState.saving;

  Future<void> _performSave(T newValue) async {
    final current = widget.delegate.valueGetter();
    if (newValue == current) {
      setState(() => _state = _EditState.view);
      return;
    }
    setState(() => _state = _EditState.saving);
    final sms = ScaffoldMessenger.of(context);
    final locs = AppLocalizations.of(context)!;
    try {
      await widget.delegate.valueSetter(newValue);
      sms.showSnackBar(SnackBar(
        content: Text(locs.settingsSuccessfullyUpdated),
        duration: const Duration(milliseconds: 1200),
      ));
    } catch (e) {
      notifyUserOfErrorX(
        scaffoldMessenger: sms,
        errorSituation: widget.delegate.errorSituation,
        appLocalizations: locs,
        exception: e,
      );
    } finally {
      if (mounted) setState(() => _state = _EditState.view);
    }
  }

  Future<void> _openDialogEditor() async {
    final initial = widget.delegate.valueGetter();
    final T? result = await showDialog<T>(
      context: context,
      barrierDismissible: true,
      builder: (ctx) {
        return Dialog(
          insetPadding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(28)),
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: widget.delegate.buildEditor(
              ctx,
              initial,
              (v) => Navigator.of(ctx).pop(v),
              () => Navigator.of(ctx).pop(),
              _isSaving,
            ),
          ),
        );
      },
    );
    if (result != null) await _performSave(result);
  }

  @override
  Widget build(BuildContext context) {
    final delegate = widget.delegate;
    final current = delegate.valueGetter();

    // Диалоговый режим
    if (delegate.useDialogEditor) {
      return SettingsTile.navigation(
        leading: Icon(delegate.icon),
        title: Text(delegate.title),
        value: delegate.buildView(context, current),
        onPressed: (_) => _openDialogEditor(),
      );
    }

    // Inline-режим (под заголовком будет редактор прямо в tile)
    return SettingsTile.navigation(
      leading: Icon(delegate.icon),
      title: Text(delegate.title),
      value: _state == _EditState.view
          ? delegate.buildView(context, current)
          : delegate.buildEditor(
              context,
              current,
              _performSave,
              () => setState(() => _state = _EditState.view),
              _isSaving,
            ),
      onPressed: (_) {
        if (_state == _EditState.view) setState(() => _state = _EditState.edit);
      },
    );
  }
}
