// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only

/// Renders the shared Settings dialog for the FocusFlow Flutter UI.
library;

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

import '../../theme/focus_flow_tokens.dart';

/// Time zone codes recognized by the app's runtime config loader.
const _timeZoneOptions = <String>[
  'UTC',
  'GMT',
  'PST',
  'PDT',
  'MST',
  'MDT',
  'CST',
  'CDT',
  'EST',
  'EDT',
];

/// Dialog that surfaces persisted [OwnerSettings] fields for editing.
///
/// Returns an [OwnerSettingsUpdate] patch containing only the fields the user
/// changed when confirmed, or `null` when cancelled.
class SettingsDialog extends StatefulWidget {
  /// Creates a settings dialog seeded with the currently persisted [initial]
  /// settings.
  const SettingsDialog({required this.initial, super.key});

  /// Currently persisted owner settings shown as the dialog's starting
  /// values.
  final OwnerSettings initial;

  /// Creates the mutable state object used by this stateful widget.
  /// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin.
  @override
  State<SettingsDialog> createState() => _SettingsDialogState();
}

/// Private implementation type for `_SettingsDialogState` in this library.
class _SettingsDialogState extends State<SettingsDialog> {
  late String _timeZoneId;
  late WallTime _dayStart;
  late WallTime _dayEnd;
  late bool _compactModeEnabled;
  late final TextEditingController _freshDaysController;
  late final TextEditingController _agingDaysController;

  /// Validation message for the day window, if any.
  String? _dayWindowError;

  /// Validation message for the staleness thresholds, if any.
  String? _stalenessError;

  /// Initializes state owned by this object before the first build.
  /// Use this lifecycle point for controller setup, initial reads, and listener wiring that must happen once per mounted instance.
  @override
  void initState() {
    super.initState();
    final initial = widget.initial;
    _timeZoneId = _timeZoneOptions.contains(initial.timeZoneId.toUpperCase())
        ? initial.timeZoneId.toUpperCase()
        : _timeZoneOptions.first;
    _dayStart = initial.dayStart;
    _dayEnd = initial.dayEnd;
    _compactModeEnabled = initial.compactModeEnabled;
    _freshDaysController = TextEditingController(
      text: initial.backlogStalenessSettings.greenMaxAge.inDays.toString(),
    );
    _agingDaysController = TextEditingController(
      text: initial.backlogStalenessSettings.blueMaxAge.inDays.toString(),
    );
  }

  /// Releases resources owned by this object before it leaves the tree.
  /// Controllers, listeners, and other disposable collaborators should be cleaned up here to avoid stale callbacks.
  @override
  void dispose() {
    _freshDaysController.dispose();
    _agingDaysController.dispose();
    super.dispose();
  }

  Future<void> _pickDayStart() async {
    final picked = await showTimePicker(
      context: context,
      initialTime: TimeOfDay(hour: _dayStart.hour, minute: _dayStart.minute),
    );
    if (picked == null) {
      return;
    }
    setState(() {
      _dayStart = WallTime(hour: picked.hour, minute: picked.minute);
      _dayWindowError = null;
    });
  }

  Future<void> _pickDayEnd() async {
    final picked = await showTimePicker(
      context: context,
      initialTime: TimeOfDay(hour: _dayEnd.hour, minute: _dayEnd.minute),
    );
    if (picked == null) {
      return;
    }
    setState(() {
      _dayEnd = WallTime(hour: picked.hour, minute: picked.minute);
      _dayWindowError = null;
    });
  }

  void _submit() {
    if (_dayStart.compareTo(_dayEnd) >= 0) {
      setState(() => _dayWindowError = 'Day end must be after day start.');
      return;
    }
    final freshDays = int.tryParse(_freshDaysController.text.trim());
    final agingDays = int.tryParse(_agingDaysController.text.trim());
    if (freshDays == null ||
        agingDays == null ||
        freshDays < 0 ||
        agingDays < freshDays) {
      setState(
        () => _stalenessError =
            'Aging must be a number of days at least as large as Fresh.',
      );
      return;
    }

    Navigator.of(context).pop(
      OwnerSettingsUpdate(
        timeZoneId: _timeZoneId,
        dayStart: _dayStart,
        dayEnd: _dayEnd,
        compactModeEnabled: _compactModeEnabled,
        backlogStalenessSettings: BacklogStalenessSettings(
          greenMaxAge: Duration(days: freshDays),
          blueMaxAge: Duration(days: agingDays),
        ),
      ),
    );
  }

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      backgroundColor: FocusFlowTokens.elevatedPanel,
      title: const Text(
        'Settings',
        style: TextStyle(color: FocusFlowTokens.textPrimary),
      ),
      content: SizedBox(
        width: 420,
        child: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'Time & day',
                style: TextStyle(
                  color: FocusFlowTokens.textPrimary,
                  fontWeight: FontWeight.w700,
                ),
              ),
              const SizedBox(height: 8),
              DropdownButtonFormField<String>(
                key: const ValueKey('settings-timezone'),
                initialValue: _timeZoneId,
                decoration: const InputDecoration(labelText: 'Time zone'),
                items: [
                  for (final zone in _timeZoneOptions)
                    DropdownMenuItem(value: zone, child: Text(zone)),
                ],
                onChanged: (value) {
                  if (value == null) {
                    return;
                  }
                  setState(() => _timeZoneId = value);
                },
              ),
              const SizedBox(height: 12),
              Row(
                children: [
                  Expanded(
                    child: OutlinedButton(
                      key: const ValueKey('settings-day-start'),
                      onPressed: _pickDayStart,
                      child: Text('Day start: ${_dayStart.formatted}'),
                    ),
                  ),
                  const SizedBox(width: 8),
                  Expanded(
                    child: OutlinedButton(
                      key: const ValueKey('settings-day-end'),
                      onPressed: _pickDayEnd,
                      child: Text('Day end: ${_dayEnd.formatted}'),
                    ),
                  ),
                ],
              ),
              if (_dayWindowError != null) ...[
                const SizedBox(height: 6),
                Text(
                  _dayWindowError!,
                  style: const TextStyle(color: FocusFlowTokens.accentMagenta),
                ),
              ],
              const SizedBox(height: 20),
              const Text(
                'Compact mode',
                style: TextStyle(
                  color: FocusFlowTokens.textPrimary,
                  fontWeight: FontWeight.w700,
                ),
              ),
              SwitchListTile(
                key: const ValueKey('settings-compact-mode'),
                contentPadding: EdgeInsets.zero,
                title: const Text(
                  'Compact Today view',
                  style: TextStyle(color: FocusFlowTokens.textPrimary),
                ),
                subtitle: const Text(
                  'Saved now; visual toggle is coming soon.',
                  style: TextStyle(
                    color: FocusFlowTokens.textMuted,
                    fontSize: 12,
                  ),
                ),
                value: _compactModeEnabled,
                onChanged: (value) {
                  setState(() => _compactModeEnabled = value);
                },
              ),
              const SizedBox(height: 20),
              const Text(
                'Backlog freshness',
                style: TextStyle(
                  color: FocusFlowTokens.textPrimary,
                  fontWeight: FontWeight.w700,
                ),
              ),
              const SizedBox(height: 8),
              Row(
                children: [
                  Expanded(
                    child: TextField(
                      key: const ValueKey('settings-fresh-days'),
                      controller: _freshDaysController,
                      keyboardType: TextInputType.number,
                      decoration: const InputDecoration(
                        labelText: 'Fresh (days)',
                      ),
                      onChanged: (_) => setState(() => _stalenessError = null),
                    ),
                  ),
                  const SizedBox(width: 8),
                  Expanded(
                    child: TextField(
                      key: const ValueKey('settings-aging-days'),
                      controller: _agingDaysController,
                      keyboardType: TextInputType.number,
                      decoration: const InputDecoration(
                        labelText: 'Aging (days)',
                      ),
                      onChanged: (_) => setState(() => _stalenessError = null),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 4),
              const Text(
                'Anything older than Aging is shown as Stale.',
                style: TextStyle(
                  color: FocusFlowTokens.textMuted,
                  fontSize: 12,
                ),
              ),
              if (_stalenessError != null) ...[
                const SizedBox(height: 6),
                Text(
                  _stalenessError!,
                  style: const TextStyle(color: FocusFlowTokens.accentMagenta),
                ),
              ],
            ],
          ),
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        FilledButton(
          key: const ValueKey('settings-save'),
          onPressed: _submit,
          child: const Text('Save'),
        ),
      ],
    );
  }
}

/// Formats a [WallTime] as `HH:MM`.
extension on WallTime {
  String get formatted =>
      '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}';
}
