import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';

import '../../about/external/data/Commitment.dart';
import '../../about/external/initial/CompletionRequest.dart';
import '../../about/internal/application/CommitmentClass.dart';
import '../../about/internal/application/NotificationType.dart';
import '../../about/internal/application/ProofType.dart';
import '../../about/internal/application/Standing.dart';
import '../../about/internal/application/TextType.dart';
import '../../designs/Checkbox.dart';
import '../../designs/Component.dart';
import '../../designs/Responsive.dart';
import '../../designs/Shell.dart';
import '../../designs/buttons/Buttons.dart';
import '../../designs/input/InputFields.dart';
import '../../designs/text/Text.dart';
import '../../utils/Colors.dart';
import '../../utils/CommonUtils.dart';
import '../../utils/DebtEngine.dart';
import '../../utils/Thresholds.dart';
import '../../utils/Validators.dart';
import 'ConnectOverdueQueue.dart';
import 'OverdueQueue.dart';
import 'ViewOverdueQueue.dart';

class OverdueQueueState extends State<OverdueQueue>
    implements ConnectOverdueQueue {
  ViewOverdueQueue? _model;

  List<Commitment> _queue = <Commitment>[];

  Standing _standing = Standing.Good;

  double _debt = 0;

  bool _changed = false;

  /// Ticked locally, awaiting the server. Rolls back on failure.
  final Set<String> _ticked = <String>{};

  @override
  Widget build(BuildContext context) {
    return ViewModelBuilder<ViewOverdueQueue>.reactive(
      viewModelBuilder: () => ViewOverdueQueue(context, this),
      onViewModelReady: (viewModel) {
        _model = viewModel;
        _initiate();
      },
      builder: (context, viewModel, child) => LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
          return Responsive(
            mobile: _mobileView(constraints),
            tablet: _mobileView(constraints),
            desktop: _mobileView(constraints),
          );
        },
      ),
    );
  }

  void _initiate() {
    _model?.loadQueue();
  }

  // ── Handlers ──────────────────────────────────────────────────────────────

  void _onBack() {
    Navigator.pop(context, _changed);
  }

  /// The tick completes the item outright. The Complete button still runs the
  /// proof flow, so a task that needs an artefact has a route that asks for
  /// one — the tick is the quick path, not the only one.
  void _onTick(Commitment item) {
    if (item.id == null || _ticked.contains(item.id)) {
      return;
    }

    setState(() {
      _ticked.add(item.id!);
    });

    _model?.complete(
      item,
      CompletionRequest(
        commitmentId: item.id ?? "",
        proofType: item.proofType.name,
      ),
    );
  }

  void _onComplete(Commitment item) {
    // Honour proof settles immediately; everything else has to produce its
    // artefact before the completion is accepted.
    if (item.proofType == ProofType.Honour) {
      _model?.complete(
        item,
        CompletionRequest(
          commitmentId: item.id ?? "",
          proofType: item.proofType.name,
        ),
      );
      return;
    }

    _openProofSheet(item);
  }

  void _onDefer(Commitment item) {
    _openDeferralSheet(item);
  }

  void _onAbandon(Commitment item) {
    _openAbandonSheet(item);
  }

  void _onAmnesty(Commitment item) {
    _model?.spendAmnesty(item);
  }

  // ── Sheets ────────────────────────────────────────────────────────────────

  /// The deferral sheet. The excuse field is the whole point of the screen —
  /// free text, minimum length, no template buttons to route around it.
  void _openDeferralSheet(Commitment item) {
    final TextEditingController excuse = TextEditingController();
    final GlobalKey<FormState> formKey = GlobalKey<FormState>();

    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      barrierColor: colorPrimaryDark.withValues(alpha: 0.6),
      builder: (BuildContext sheetContext) {
        return StatefulBuilder(
          builder: (BuildContext sheetContext, StateSetter setSheetState) {
            final int remaining =
                Thresholds.maxDeferralsPerTask - item.deferralCount;

            return Padding(
              padding: EdgeInsets.only(
                bottom: MediaQuery.of(sheetContext).viewInsets.bottom,
              ),
              child: Container(
                decoration: BoxDecoration(
                  color: colorSheetBackground,
                  borderRadius: const BorderRadius.only(
                    topLeft: Radius.circular(28),
                    topRight: Radius.circular(28),
                  ),
                ),
                child: SingleChildScrollView(
                  padding: const EdgeInsets.fromLTRB(24, 16, 24, 32),
                  child: Form(
                    key: formKey,
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: [
                        Center(
                          child: Container(
                            width: 36,
                            height: 4,
                            margin: const EdgeInsets.only(bottom: 20),
                            decoration: BoxDecoration(
                              color: colorGrey.withValues(alpha: 0.35),
                              borderRadius: BorderRadius.circular(999),
                            ),
                          ),
                        ),
                        text("DEFERRING", 9, TextType.Bold,
                            color: colorGrey2, letterSpacing: 1.2),
                        const SizedBox(height: 10),
                        text(item.title, 26, TextType.Light,
                            color: colorPrimaryDark, height: 1.2),
                        const SizedBox(height: 14),
                        text(
                          remaining <= 1
                              ? "This is the last deferral this task gets. After it, the only options are completing or abandoning."
                              : "$remaining deferrals left on this task.",
                          13,
                          TextType.Regular,
                          color: colorGrey2,
                          height: 1.5,
                        ),
                        const SizedBox(height: 24),
                        excuseField(
                          excuse,
                          Thresholds.minExcuseLength,
                          validator: Validators.excuse,
                          onChanged: (value) => setSheetState(() {}),
                        ),
                        const SizedBox(height: 24),
                        roundedCornerButton(
                          "Defer with this reason",
                          () {
                            if (formKey.currentState?.validate() != true) {
                              return;
                            }
                            Navigator.pop(sheetContext);
                            _model?.defer(item, excuse.text);
                          },
                          icon: CupertinoIcons.clock,
                        ),
                        const SizedBox(height: 8),
                        Center(
                          child: textButton(
                            "Cancel",
                            () => Navigator.pop(sheetContext),
                            textSize: 13,
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            );
          },
        );
      },
    );
  }

  void _openAbandonSheet(Commitment item) {
    final TextEditingController reason = TextEditingController();
    final GlobalKey<FormState> formKey = GlobalKey<FormState>();

    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      barrierColor: colorPrimaryDark.withValues(alpha: 0.6),
      builder: (BuildContext sheetContext) {
        return Padding(
          padding: EdgeInsets.only(
            bottom: MediaQuery.of(sheetContext).viewInsets.bottom,
          ),
          child: Container(
            decoration: BoxDecoration(
              color: colorSheetBackground,
              borderRadius: const BorderRadius.only(
                topLeft: Radius.circular(28),
                topRight: Radius.circular(28),
              ),
            ),
            child: SingleChildScrollView(
              padding: const EdgeInsets.fromLTRB(24, 16, 24, 32),
              child: Form(
                key: formKey,
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    Center(
                      child: Container(
                        width: 36,
                        height: 4,
                        margin: const EdgeInsets.only(bottom: 20),
                        decoration: BoxDecoration(
                          color: colorGrey.withValues(alpha: 0.35),
                          borderRadius: BorderRadius.circular(999),
                        ),
                      ),
                    ),
                    text("ABANDONING", 9, TextType.Bold,
                        color: colorStandingLockdown, letterSpacing: 1.2),
                    const SizedBox(height: 10),
                    text(item.title, 26, TextType.Light,
                        color: colorPrimaryDark, height: 1.2),
                    const SizedBox(height: 14),
                    card(
                      background: colorStandingLockdownBg,
                      borderColor:
                          colorStandingLockdown.withValues(alpha: 0.20),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          text("THE COST", 9, TextType.Bold,
                              color: colorStandingLockdown, letterSpacing: 1.2),
                          const SizedBox(height: 8),
                          text(
                            "Abandoning is the most expensive outcome there is. It costs double weight and will not decay for 30 days.",
                            13,
                            TextType.Regular,
                            color: colorPrimaryDark,
                            height: 1.5,
                          ),
                        ],
                      ),
                    ),
                    const SizedBox(height: 20),
                    inputField(
                      "Reason",
                      reason,
                      hint: "Why is this never happening?",
                      validator: Validators.excuse,
                      maxLines: 3,
                    ),
                    const SizedBox(height: 24),
                    destructiveButton(
                      "Abandon permanently",
                      () {
                        if (formKey.currentState?.validate() != true) {
                          return;
                        }
                        Navigator.pop(sheetContext);
                        _model?.abandon(item, reason.text);
                      },
                      icon: CupertinoIcons.xmark_circle,
                    ),
                    const SizedBox(height: 8),
                    Center(
                      child: textButton(
                        "Keep it",
                        () => Navigator.pop(sheetContext),
                        textSize: 13,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        );
      },
    );
  }

  /// Proof types other than Honour need their artefact. The sheet states what
  /// is required rather than letting the user tap a checkbox and move on.
  void _openProofSheet(Commitment item) {
    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      barrierColor: colorPrimaryDark.withValues(alpha: 0.6),
      builder: (BuildContext sheetContext) {
        return Container(
          decoration: BoxDecoration(
            color: colorSheetBackground,
            borderRadius: const BorderRadius.only(
              topLeft: Radius.circular(28),
              topRight: Radius.circular(28),
            ),
          ),
          child: SingleChildScrollView(
            padding: const EdgeInsets.fromLTRB(24, 16, 24, 32),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Center(
                  child: Container(
                    width: 36,
                    height: 4,
                    margin: const EdgeInsets.only(bottom: 20),
                    decoration: BoxDecoration(
                      color: colorGrey.withValues(alpha: 0.35),
                      borderRadius: BorderRadius.circular(999),
                    ),
                  ),
                ),
                text("PROOF REQUIRED", 9, TextType.Bold,
                    color: colorGrey2, letterSpacing: 1.2),
                const SizedBox(height: 10),
                text(proofLabel(item.proofType), 26, TextType.Light,
                    color: colorPrimaryDark, height: 1.2),
                const SizedBox(height: 14),
                text(
                  _proofDescription(item),
                  14,
                  TextType.Regular,
                  color: colorGrey2,
                  height: 1.55,
                ),
                const SizedBox(height: 24),
                roundedCornerButton(
                  _proofAction(item.proofType),
                  () {
                    Navigator.pop(sheetContext);
                    _model?.complete(
                      item,
                      CompletionRequest(
                        commitmentId: item.id ?? "",
                        proofType: item.proofType.name,
                      ),
                    );
                  },
                  icon: _proofIcon(item.proofType),
                ),
                const SizedBox(height: 8),
                Center(
                  child: textButton(
                    "Not now",
                    () => Navigator.pop(sheetContext),
                    textSize: 13,
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  String _proofDescription(Commitment item) {
    switch (item.proofType) {
      case ProofType.Honour:
        return "Your word is enough for this one.";
      case ProofType.Photo:
        return "Camera only — no gallery imports. The timestamp is embedded and near-duplicate submissions are flagged.";
      case ProofType.Timer:
        return "A foreground session of at least ${item.proofTimerMinutes} minutes. Leaving the app pauses the clock.";
      case ProofType.Location:
        return "You need to have actually been there. Dwell time inside the geofence counts, passing by does not.";
      case ProofType.Health:
        return "Your health platform has to confirm a workout inside the window.";
      case ProofType.Witness:
        return "Your accountability partner confirms this one.";
    }
  }

  String _proofAction(ProofType type) {
    switch (type) {
      case ProofType.Honour:
        return "Mark complete";
      case ProofType.Photo:
        return "Open camera";
      case ProofType.Timer:
        return "Start the timer";
      case ProofType.Location:
        return "Check my location";
      case ProofType.Health:
        return "Check health data";
      case ProofType.Witness:
        return "Request confirmation";
    }
  }

  IconData _proofIcon(ProofType type) {
    switch (type) {
      case ProofType.Honour:
        return CupertinoIcons.checkmark;
      case ProofType.Photo:
        return CupertinoIcons.camera_fill;
      case ProofType.Timer:
        return CupertinoIcons.timer;
      case ProofType.Location:
        return CupertinoIcons.location_fill;
      case ProofType.Health:
        return CupertinoIcons.heart_fill;
      case ProofType.Witness:
        return CupertinoIcons.person_2_fill;
    }
  }

  // ── Views ─────────────────────────────────────────────────────────────────

  Widget _mobileView(BoxConstraints constraints) {
    return Sheet(
      eyebrow: "Outstanding",
      title: "What you owe",
      chrome: _queue.isEmpty ? colorPrimaryDark : standingColor(_standing),
      onBack: _onBack,
      banner: _debtBanner(),
      child: _queue.isEmpty
          ? emptyState(
              CupertinoIcons.checkmark_seal,
              "Nothing outstanding",
              "The queue is empty. Your standing recovers as the remaining debt decays.",
              accent: colorPositive,
            )
          : Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              mainAxisSize: MainAxisSize.min,
              children: [
                sectionBreak(
                  "The queue",
                  caption: "oldest first",
                  trailing: pill(
                    "${_queue.length} / ${Thresholds.maxOpenOverdue}",
                    _queue.length >= Thresholds.maxOpenOverdue
                        ? colorStandingGrounded
                        : colorGrey2,
                    _queue.length >= Thresholds.maxOpenOverdue
                        ? colorStandingGroundedBg
                        : colorMuted,
                    textSize: 9,
                  ),
                ),
                ..._queue.map(_queueRow),
              ],
            ),
    );
  }

  Widget _debtBanner() {
    return Container(
      padding: const EdgeInsets.fromLTRB(16, 14, 16, 14),
      decoration: BoxDecoration(
        color: colorWhite.withValues(alpha: 0.10),
        borderRadius: BorderRadius.circular(16),
      ),
      child: Row(
        children: [
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                text("TOTAL DEBT", 9, TextType.Bold,
                    color: colorWhite.withValues(alpha: 0.55),
                    letterSpacing: 1.2),
                const SizedBox(height: 6),
                text(formatDebt(_debt), 32, TextType.Light, color: colorWhite),
              ],
            ),
          ),
          Column(
            crossAxisAlignment: CrossAxisAlignment.end,
            mainAxisSize: MainAxisSize.min,
            children: [
              text("STANDING", 9, TextType.Bold,
                  color: colorWhite.withValues(alpha: 0.55),
                  letterSpacing: 1.2),
              const SizedBox(height: 6),
              text(standingLabel(_standing), 15, TextType.Medium,
                  color: colorWhite),
            ],
          ),
        ],
      ),
    );
  }

  Widget _queueRow(Commitment item) {
    final Color accent = classColor(item.commitmentClass);

    final bool deferrable =
        item.deferrableUnder(Thresholds.maxDeferralsPerTask);

    return Container(
      margin: const EdgeInsets.only(bottom: 12),
      child: card(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: [
            TickRow(
              checked: _ticked.contains(item.id),
              title: item.title,
              accent: accent,
              onTick: () => _onTick(item),
              detail: text(formatWindow(item), 11, TextType.Regular,
                  color: colorGrey2),
              trailing: pill(
                classLabel(item.commitmentClass),
                accent,
                classBackground(item.commitmentClass),
                textSize: 9,
              ),
            ),
            const SizedBox(height: 16),
            Row(
              children: [
                Expanded(
                  child: labelled(
                    "Overdue",
                    overdueLabel(item),
                    valueSize: 13,
                    valueColor: colorStandingGrounded,
                  ),
                ),
                Expanded(
                  child: labelled(
                    "Costing",
                    formatDebt(DebtEngine.commitmentDebt(item)),
                    valueSize: 13,
                  ),
                ),
                Expanded(
                  child: labelled(
                    "Deferred",
                    "${item.deferralCount}/${Thresholds.maxDeferralsPerTask}",
                    valueSize: 13,
                    valueColor:
                        deferrable ? colorPrimaryDark : colorStandingGrounded,
                  ),
                ),
              ],
            ),
            hairline(margin: const EdgeInsets.symmetric(vertical: 16)),
            Row(
              children: [
                Expanded(
                  child: roundedCornerButton(
                    "Complete",
                    () => _onComplete(item),
                    icon: CupertinoIcons.checkmark,
                    verticalPadding: 13,
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  child: outlinedActionButton(
                    deferrable ? "Defer" : "No deferrals",
                    () => _onDefer(item),
                    enabled: deferrable &&
                        item.commitmentClass != CommitmentClass.NonNegotiable,
                    icon: CupertinoIcons.clock,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 6),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                textButton("Amnesty", () => _onAmnesty(item),
                    textSize: 12, color: colorGrey2),
                textButton("Abandon", () => _onAbandon(item),
                    textSize: 12, color: colorStandingLockdown),
              ],
            ),
          ],
        ),
      ),
    );
  }

  // ── ConnectOverdueQueue ───────────────────────────────────────────────────

  @override
  void onQueueLoaded(List<Commitment> queue, Standing standing, double debt) {
    setState(() {
      _ticked.removeWhere((id) => queue.every((item) => item.id != id));
      _queue = queue;
      _standing = standing;
      _debt = debt;
    });
  }

  @override
  void onItemCleared(Commitment item, double reliefApplied, String verb) {
    _changed = true;

    _model?.showApplicationNotification(
      verb == "Abandoned"
          ? NotificationType.warning
          : NotificationType.success,
      verb,
      verb == "Late complete"
          ? "Recorded as a late complete. It reduces the debt but does not clear it — the miss stays in your history."
          : reliefApplied > 0
              ? "${formatDebt(reliefApplied)} came off your debt."
              : "Recorded.",
      true,
      true,
      null,
    );
  }

  @override
  void onDeferralRefused(String reason) {
    _model?.showApplicationNotification(
      NotificationType.warning,
      "Not deferrable",
      reason,
      true,
      true,
      null,
    );
  }

  @override
  void onAmnestySpent(int remaining) {
    _changed = true;

    _model?.showApplicationNotification(
      NotificationType.success,
      "Amnesty applied",
      "No questions asked. $remaining token${remaining == 1 ? "" : "s"} left this month.",
      true,
      true,
      null,
    );
  }

  @override
  void onAmnestyRefused() {
    _model?.showApplicationNotification(
      NotificationType.info,
      "No tokens left",
      "You have spent this month's amnesty. They reset at the start of next month.",
      true,
      true,
      null,
    );
  }
}
