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

part of '../focus_flow_app.dart';

/// Private implementation type for `_FocusFlowHomeState` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _FocusFlowHomeState extends State<FocusFlowHome> {
  /// Stores the `todayController` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  late final TodayScreenController todayController;

  /// Stores the `backlogController` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  late final BacklogBoardController backlogController;

  /// Stores the `selectedDateController` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  late final SelectedDateController selectedDateController;

  /// Stores the `commandController` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  late final SchedulerCommandController commandController;

  /// Private state stored as `_activeSection` for this implementation.
  /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
  FocusFlowSection _activeSection = FocusFlowSection.today;

  /// 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();
    logger.debug(() => 'FocusFlow home initializing controllers.');
    selectedDateController = widget.composition.createSelectedDateController();
    todayController = widget.composition.createTodayScreenController(
      selectedDates: selectedDateController,
    );
    backlogController = widget.composition.createBacklogBoardController(
      selectedDates: selectedDateController,
    );
    commandController = widget.composition.createCommandController(
      refreshReads: _refreshReads,
      selectedDate: () => selectedDateController.date,
    );
    logger.finer(() => 'FocusFlow home triggering initial Today load.');
    todayController.load();
  }

  /// 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() {
    logger.debug(() => 'FocusFlow home disposing controllers.');
    commandController.dispose();
    backlogController.dispose();
    todayController.dispose();
    selectedDateController.dispose();
    unawaited(widget.composition.dispose());
    super.dispose();
  }

  /// Runs the `_toggleCardCompletion` operation and completes after its asynchronous work finishes.
  /// Callers should await the returned future so repository writes, UI refreshes, and failure handling happen in a predictable order.
  Future<void> _toggleCardCompletion(TimelineCardModel card) async {
    if (!card.canToggleCompletion) {
      logger.finer(
        () => 'Timeline completion toggle ignored. cardId=${card.id}',
      );
      return;
    }
    logger.debug(
      () =>
          'Timeline completion toggle requested. '
          'cardId=${card.id} taskType=${card.taskType.name} isCompleted=${card.isCompleted}',
    );
    if (card.isCompleted) {
      await commandController.uncompleteTask(taskId: card.id);
    } else {
      await commandController.completeTask(
        taskId: card.id,
        taskType: card.taskType,
      );
    }
  }

  /// Adds a generic filler task from the timeline context menu.
  Future<void> _addGenericFlexibleTask() async {
    logger.debug(() => 'Timeline add generic flexible task requested.');
    await commandController.addGenericFlexibleTask();
  }

  /// Pushes [card] to the next available slot after the current clock time.
  Future<void> _pushCardToNext(TimelineCardModel card) async {
    logger.debug(() => 'Timeline push-to-next requested. cardId=${card.id}');
    await commandController.pushTaskToNextAvailableSlot(
      taskId: card.id,
      expectedUpdatedAt: card.expectedUpdatedAt,
    );
  }

  /// Pushes [card] to tomorrow's first available slot.
  Future<void> _pushCardToTomorrow(TimelineCardModel card) async {
    logger.debug(
      () => 'Timeline push-to-tomorrow requested. cardId=${card.id}',
    );
    await commandController.pushTaskToTomorrow(
      taskId: card.id,
      expectedUpdatedAt: card.expectedUpdatedAt,
    );
  }

  /// Pushes [card] back to Backlog.
  Future<void> _pushCardToBacklog(TimelineCardModel card) async {
    logger.debug(() => 'Timeline push-to-backlog requested. cardId=${card.id}');
    await commandController.pushTaskToBacklog(
      taskId: card.id,
      expectedUpdatedAt: card.expectedUpdatedAt,
    );
  }

  /// Permanently removes [card] from persistence.
  Future<void> _removeCard(TimelineCardModel card) async {
    logger.debug(() => 'Timeline remove requested. cardId=${card.id}');
    await commandController.removeTask(
      taskId: card.id,
      expectedUpdatedAt: card.expectedUpdatedAt,
    );
    todayController.clearSelection();
  }

  /// Refreshes every read surface affected by scheduler commands.
  Future<void> _refreshReads() async {
    await Future.wait([todayController.load(), backlogController.load()]);
  }

  /// Selects the visible app [section].
  void _selectSection(FocusFlowSection section) {
    if (section == _activeSection) {
      return;
    }
    logger.debug(() => 'FocusFlow section selected. section=${section.name}');
    setState(() {
      _activeSection = section;
    });
    if (section == FocusFlowSection.backlog) {
      unawaited(backlogController.load());
    }
  }

  /// Moves the visible planning date backward by one day.
  void _selectPreviousDate() {
    logger.finer(() => 'Previous date action requested.');
    selectedDateController.selectPreviousDay();
  }

  /// Moves the visible planning date forward by one day.
  void _selectNextDate() {
    logger.finer(() => 'Next date action requested.');
    selectedDateController.selectNextDay();
  }

  /// Opens the date picker and selects the chosen owner-local civil date.
  Future<void> _chooseDate() async {
    final picked = await showDatePicker(
      context: context,
      initialDate: _dateTimeForCivilDate(selectedDateController.date),
      firstDate: DateTime(2000),
      lastDate: DateTime(2100),
      builder: _buildDatePickerTheme,
    );
    if (picked == null) {
      logger.finer(() => 'Date picker dismissed without selection.');
      return;
    }
    final selected = _civilDateForDateTime(picked);
    logger.debug(
      () => 'Date picker selected date. date=${selected.toIsoString()}',
    );
    selectedDateController.selectDate(selected);
  }

  /// 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 Scaffold(
      backgroundColor: FocusFlowTokens.appBackground,
      body: AppShell(
        sidebar: Sidebar(
          activeSection: _activeSection,
          onSectionSelected: _selectSection,
        ),
        child: switch (_activeSection) {
          FocusFlowSection.today => _buildTodayScreen(),
          FocusFlowSection.backlog => BacklogBoardScreen(
            controller: backlogController,
          ),
          FocusFlowSection.projects ||
          FocusFlowSection.reports ||
          FocusFlowSection.settings => _SectionPlaceholder(
            section: _activeSection,
          ),
        },
      ),
    );
  }

  /// Builds the current Today screen branch.
  Widget _buildTodayScreen() {
    return AnimatedBuilder(
      animation: todayController,
      builder: (context, _) {
        return switch (todayController.state) {
          TodayScreenLoading() => const Center(
            child: CircularProgressIndicator(),
          ),
          TodayScreenFailure(:final message) => _PlanIssue(message: message),
          TodayScreenEmpty(:final data) => _TodayScreenScaffold(
            data: data,
            selectedCard: todayController.selectedCard,
            onSelectCard: todayController.selectCard,
            onCompleteCard: _toggleCardCompletion,
            onPushToNext: _pushCardToNext,
            onPushToTomorrow: _pushCardToTomorrow,
            onPushToBacklog: _pushCardToBacklog,
            onRemoveCard: _removeCard,
            onAddTask: _addGenericFlexibleTask,
            onClearSelection: todayController.clearSelection,
            onPreviousDate: _selectPreviousDate,
            onNextDate: _selectNextDate,
            onChooseDate: () {
              unawaited(_chooseDate());
            },
          ),
          TodayScreenReady(:final data) => _TodayScreenScaffold(
            data: data,
            selectedCard: todayController.selectedCard,
            onSelectCard: todayController.selectCard,
            onCompleteCard: _toggleCardCompletion,
            onPushToNext: _pushCardToNext,
            onPushToTomorrow: _pushCardToTomorrow,
            onPushToBacklog: _pushCardToBacklog,
            onRemoveCard: _removeCard,
            onAddTask: _addGenericFlexibleTask,
            onClearSelection: todayController.clearSelection,
            onPreviousDate: _selectPreviousDate,
            onNextDate: _selectNextDate,
            onChooseDate: () {
              unawaited(_chooseDate());
            },
          ),
        };
      },
    );
  }

  /// Builds the dark theme wrapper used by the date picker dialog.
  Widget _buildDatePickerTheme(BuildContext context, Widget? child) {
    final theme = Theme.of(context);
    return Theme(
      data: theme.copyWith(
        colorScheme: theme.colorScheme.copyWith(
          primary: FocusFlowTokens.accentMagenta,
          onPrimary: FocusFlowTokens.textPrimary,
          surface: FocusFlowTokens.elevatedPanel,
          onSurface: FocusFlowTokens.textPrimary,
        ),
        dialogTheme: theme.dialogTheme.copyWith(
          backgroundColor: FocusFlowTokens.elevatedPanel,
        ),
      ),
      child: child ?? const SizedBox.shrink(),
    );
  }

  /// Converts [date] into a local DateTime for Flutter's date picker.
  DateTime _dateTimeForCivilDate(CivilDate date) {
    return DateTime(date.year, date.month, date.day);
  }

  /// Converts [dateTime] into a civil date without applying a timezone shift.
  CivilDate _civilDateForDateTime(DateTime dateTime) {
    return CivilDate(dateTime.year, dateTime.month, dateTime.day);
  }
}

/// Placeholder for navigation sections that are not part of the V1 screen work.
class _SectionPlaceholder extends StatelessWidget {
  /// Creates a placeholder for [section].
  const _SectionPlaceholder({required this.section});

  /// Section represented by this placeholder.
  final FocusFlowSection section;

  /// 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 Center(
      child: DecoratedBox(
        decoration: BoxDecoration(
          color: FocusFlowTokens.panelBackground,
          borderRadius: BorderRadius.circular(8),
          border: Border.all(color: FocusFlowTokens.subtleBorder),
        ),
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 24),
          child: Text(
            _labelFor(section),
            style: Theme.of(context).textTheme.headlineSmall?.copyWith(
              color: FocusFlowTokens.textPrimary,
              fontWeight: FontWeight.w800,
            ),
          ),
        ),
      ),
    );
  }

  /// Resolves display text for [section].
  String _labelFor(FocusFlowSection section) {
    return switch (section) {
      FocusFlowSection.today => 'Today',
      FocusFlowSection.backlog => 'Backlog',
      FocusFlowSection.projects => 'Projects',
      FocusFlowSection.reports => 'Reports',
      FocusFlowSection.settings => 'Settings',
    };
  }
}
