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

/// Renders the shared Break Up 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';

/// Editable child-task row state owned by [BreakUpDialog].
class _BreakUpRow {
  /// Creates an empty break-up row with fresh text controllers.
  _BreakUpRow()
    : titleController = TextEditingController(),
      durationController = TextEditingController();

  /// Controls the row's child task title field.
  final TextEditingController titleController;

  /// Controls the row's optional duration-in-minutes field.
  final TextEditingController durationController;

  /// Optional priority selected for this row.
  PriorityLevel? priority;

  /// Reward level selected for this row.
  RewardLevel reward = RewardLevel.notSet;

  /// Releases the text controllers owned by this row.
  void dispose() {
    titleController.dispose();
    durationController.dispose();
  }
}

/// Dialog that collects one or more child task drafts to break up a parent
/// task, per MVP-AC-11 (row-level priority, reward, and duration).
///
/// Shared by the task selection modal and timeline card quick actions so
/// both surfaces reuse the same break-up flow instead of duplicating it.
class BreakUpDialog extends StatefulWidget {
  /// Creates a break-up dialog.
  const BreakUpDialog({super.key});

  /// 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<BreakUpDialog> createState() => _BreakUpDialogState();
}

/// Private implementation type for `_BreakUpDialogState` in this library.
/// It owns the growable list of child-task rows shown by the dialog.
class _BreakUpDialogState extends State<BreakUpDialog> {
  /// Editable rows currently shown in the dialog.
  final List<_BreakUpRow> _rows = [_BreakUpRow()];

  /// 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() {
    for (final row in _rows) {
      row.dispose();
    }
    super.dispose();
  }

  /// Whether at least one row has a non-empty title.
  bool get _canSubmit =>
      _rows.any((row) => row.titleController.text.trim().isNotEmpty);

  /// Appends a new empty row.
  void _addRow() {
    setState(() => _rows.add(_BreakUpRow()));
  }

  /// Removes the row at [index], keeping at least one row.
  void _removeRow(int index) {
    if (_rows.length <= 1) {
      return;
    }
    setState(() {
      _rows.removeAt(index).dispose();
    });
  }

  /// Builds child task drafts from rows with a non-empty title and closes
  /// the dialog with the resulting list.
  void _submit() {
    final drafts = <ApplicationChildTaskDraft>[
      for (final row in _rows)
        if (row.titleController.text.trim().isNotEmpty)
          ApplicationChildTaskDraft(
            title: row.titleController.text.trim(),
            priority: row.priority,
            reward: row.reward,
            durationMinutes: int.tryParse(row.durationController.text.trim()),
          ),
    ];
    Navigator.of(context).pop(drafts);
  }

  /// 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(
        'Break up task',
        style: TextStyle(color: FocusFlowTokens.textPrimary),
      ),
      content: SizedBox(
        width: 480,
        child: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              for (var i = 0; i < _rows.length; i++)
                _BreakUpRowFields(
                  key: ValueKey('break-up-row-$i'),
                  rowIndex: i,
                  row: _rows[i],
                  onChanged: () => setState(() {}),
                  onRemove: _rows.length > 1 ? () => _removeRow(i) : null,
                ),
              const SizedBox(height: 8),
              Align(
                alignment: Alignment.centerLeft,
                child: TextButton.icon(
                  key: const ValueKey('break-up-add-row'),
                  onPressed: _addRow,
                  icon: const Icon(Icons.add),
                  label: const Text('Add another task'),
                ),
              ),
            ],
          ),
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        FilledButton(
          key: const ValueKey('break-up-confirm'),
          onPressed: _canSubmit ? _submit : null,
          child: const Text('Break up'),
        ),
      ],
    );
  }
}

/// Editable fields for a single [_BreakUpRow].
class _BreakUpRowFields extends StatelessWidget {
  /// Creates fields bound to [row] at [rowIndex].
  const _BreakUpRowFields({
    required this.rowIndex,
    required this.row,
    required this.onChanged,
    this.onRemove,
    super.key,
  });

  /// Position of this row, used to build stable field keys.
  final int rowIndex;

  /// Row whose fields are rendered and mutated in place.
  final _BreakUpRow row;

  /// Invoked after any field in this row changes.
  final VoidCallback onChanged;

  /// Invoked when this row should be removed. Null when removal is disabled.
  final VoidCallback? onRemove;

  /// 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 Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Expanded(
            flex: 3,
            child: TextField(
              key: ValueKey('break-up-row-$rowIndex-title'),
              controller: row.titleController,
              decoration: const InputDecoration(labelText: 'Task title'),
              onChanged: (_) => onChanged(),
            ),
          ),
          const SizedBox(width: 8),
          SizedBox(
            width: 64,
            child: TextField(
              key: ValueKey('break-up-row-$rowIndex-duration'),
              controller: row.durationController,
              decoration: const InputDecoration(labelText: 'Min'),
              keyboardType: TextInputType.number,
              onChanged: (_) => onChanged(),
            ),
          ),
          const SizedBox(width: 8),
          SizedBox(
            width: 132,
            child: DropdownButtonFormField<PriorityLevel?>(
              key: ValueKey('break-up-row-$rowIndex-priority'),
              initialValue: row.priority,
              isExpanded: true,
              decoration: const InputDecoration(labelText: 'Priority'),
              items: [
                const DropdownMenuItem(value: null, child: Text('Unset')),
                for (final level in PriorityLevel.values)
                  DropdownMenuItem(value: level, child: Text(level.name)),
              ],
              onChanged: (value) {
                row.priority = value;
                onChanged();
              },
            ),
          ),
          const SizedBox(width: 8),
          SizedBox(
            width: 132,
            child: DropdownButtonFormField<RewardLevel>(
              key: ValueKey('break-up-row-$rowIndex-reward'),
              initialValue: row.reward,
              isExpanded: true,
              decoration: const InputDecoration(labelText: 'Reward'),
              items: [
                for (final level in RewardLevel.values)
                  DropdownMenuItem(value: level, child: Text(level.name)),
              ],
              onChanged: (value) {
                if (value == null) {
                  return;
                }
                row.reward = value;
                onChanged();
              },
            ),
          ),
          if (onRemove != null)
            IconButton(
              tooltip: 'Remove row',
              onPressed: onRemove,
              icon: const Icon(Icons.close),
            ),
        ],
      ),
    );
  }
}
