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

import '../../about/external/data/ReportCard.dart';
import '../../about/internal/application/TextType.dart';
import '../../designs/Component.dart';
import '../../designs/Responsive.dart';
import '../../designs/Shell.dart';
import '../../designs/text/Text.dart';
import '../../utils/Colors.dart';
import '../../utils/CommonUtils.dart';
import 'ConnectReportCardScreen.dart';
import 'ReportCardScreen.dart';
import 'ViewReportCardScreen.dart';

class ReportCardScreenState extends State<ReportCardScreen>
    implements ConnectReportCardScreen {
  ViewReportCardScreen? _model;

  ReportCard _report = ReportCard();

  @override
  Widget build(BuildContext context) {
    return ViewModelBuilder<ViewReportCardScreen>.reactive(
      viewModelBuilder: () => ViewReportCardScreen(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?.loadReport();
  }

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

  Widget _mobileView(BoxConstraints constraints) {
    return Sheet(
      eyebrow: "This week",
      title: "Report card",
      onBack: _onBack,
      banner: _gradeBanner(),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        mainAxisSize: MainAxisSize.min,
        children: [
          if (_report.praise.isNotEmpty) ...[
            _praiseCard(),
            const SizedBox(height: 24),
          ],
          _assignedAction(),
          const SizedBox(height: 28),
          sectionBreak("Debt", caption: "across the week"),
          _debtTrend(),
          const SizedBox(height: 28),
          sectionBreak("Completion", caption: "by class"),
          ..._report.completionByClass.entries.map(_completionRow),
          const SizedBox(height: 20),
          _worstHour(),
          const SizedBox(height: 28),
          if (_report.deferralLeaderboard.isNotEmpty) ...[
            sectionBreak("Most dodged", caption: "the leaderboard"),
            ..._report.deferralLeaderboard.take(5).map(_deferralRow),
            const SizedBox(height: 28),
          ],
          if (_report.estimationAccuracy.isNotEmpty) ...[
            sectionBreak("Your estimates", caption: "against reality"),
            ..._report.estimationAccuracy.entries.map(_estimationRow),
            const SizedBox(height: 28),
          ],
          if (_report.trainingAdherence > 0) ...[
            sectionBreak("Training"),
            _trainingCard(),
          ],
        ],
      ),
    );
  }

  /// The grade sits in the chrome. Cosmetic, but it is the thing people
  /// actually react to.
  Widget _gradeBanner() {
    return Container(
      padding: const EdgeInsets.fromLTRB(16, 14, 16, 14),
      decoration: BoxDecoration(
        color: colorWhite.withValues(alpha: 0.08),
        borderRadius: BorderRadius.circular(16),
      ),
      child: Row(
        children: [
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                text("PERIOD", 9, TextType.Bold,
                    color: colorWhite.withValues(alpha: 0.45),
                    letterSpacing: 1.2),
                const SizedBox(height: 6),
                text(
                  "${formatDate(_report.periodStart)} — ${formatDate(_report.periodEnd)}",
                  13,
                  TextType.Medium,
                  color: colorWhite,
                ),
              ],
            ),
          ),
          if (_report.grade.isNotEmpty)
            Container(
              width: 54,
              height: 54,
              alignment: Alignment.center,
              decoration: BoxDecoration(
                color: colorWhite,
                borderRadius: BorderRadius.circular(16),
              ),
              child: text(_report.grade, 26, TextType.Light,
                  color: colorPrimaryDark),
            ),
        ],
      ),
    );
  }

  /// Rationed but real. Only rendered when something specific was earned.
  Widget _praiseCard() {
    return card(
      background: colorStandingGoodBg,
      borderColor: colorPositive.withValues(alpha: 0.20),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Icon(CupertinoIcons.checkmark_seal_fill,
              size: 18, color: colorPositive),
          const SizedBox(width: 12),
          Expanded(
            child: text(_report.praise, 14, TextType.Regular,
                color: colorPrimaryDark, height: 1.55),
          ),
        ],
      ),
    );
  }

  /// One assigned action for next week. Not five.
  Widget _assignedAction() {
    return card(
      background: colorPrimaryDark,
      borderColor: colorPrimaryDark,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          text("NEXT WEEK, ONE THING", 9, TextType.Bold,
              color: colorWhite.withValues(alpha: 0.45), letterSpacing: 1.2),
          const SizedBox(height: 12),
          text(
            _report.assignedAction.isEmpty
                ? "Not enough history yet to assign anything."
                : _report.assignedAction,
            19,
            TextType.Light,
            color: colorWhite,
            height: 1.4,
          ),
        ],
      ),
    );
  }

  Widget _debtTrend() {
    if (_report.debtTrend.isEmpty) {
      return card(
        child: text("No debt recorded this week.", 13, TextType.Regular,
            color: colorGrey2),
      );
    }

    final List<FlSpot> spots = <FlSpot>[];
    for (int index = 0; index < _report.debtTrend.length; index++) {
      spots.add(FlSpot(index.toDouble(), _report.debtTrend[index]));
    }

    return card(
      padding: const EdgeInsets.fromLTRB(8, 20, 16, 8),
      child: SizedBox(
        height: 150,
        child: LineChart(
          LineChartData(
            gridData: FlGridData(
              show: true,
              drawVerticalLine: false,
              getDrawingHorizontalLine: (value) =>
                  const FlLine(color: colorChartGrid, strokeWidth: 1),
            ),
            titlesData: FlTitlesData(
              topTitles:
                  const AxisTitles(sideTitles: SideTitles(showTitles: false)),
              rightTitles:
                  const AxisTitles(sideTitles: SideTitles(showTitles: false)),
              leftTitles: const AxisTitles(
                  sideTitles: SideTitles(showTitles: true, reservedSize: 32)),
              bottomTitles:
                  const AxisTitles(sideTitles: SideTitles(showTitles: false)),
            ),
            borderData: FlBorderData(show: false),
            lineBarsData: <LineChartBarData>[
              LineChartBarData(
                spots: spots,
                isCurved: true,
                barWidth: 2.5,
                color: colorDebtLine,
                dotData: const FlDotData(show: false),
                belowBarData: BarAreaData(show: true, color: colorDebtFill),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _completionRow(MapEntry<String, double> entry) {
    return Container(
      margin: const EdgeInsets.only(bottom: 14),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              text(entry.key, 13, TextType.Medium, color: colorPrimaryDark),
              text("${(entry.value * 100).round()}%", 13, TextType.Bold,
                  color: colorGrey2),
            ],
          ),
          const SizedBox(height: 8),
          meter(
            entry.value,
            fill: entry.value >= 0.8
                ? colorPositive
                : entry.value >= 0.5
                    ? colorStandingWarned
                    : colorStandingGrounded,
          ),
        ],
      ),
    );
  }

  /// The recurring window where things go to die.
  Widget _worstHour() {
    if (_report.worstHour < 0) {
      return const SizedBox.shrink();
    }

    return card(
      background: colorStandingWarnedBg,
      borderColor: colorStandingWarned.withValues(alpha: 0.20),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          text("YOUR WORST HOUR", 9, TextType.Bold,
              color: colorStandingWarned, letterSpacing: 1.2),
          const SizedBox(height: 10),
          text(hourLabel(_report.worstHour), 30, TextType.Light,
              color: colorPrimaryDark),
          const SizedBox(height: 8),
          text(
            "This is where things go to die. Stop scheduling anything that matters into it.",
            13,
            TextType.Regular,
            color: colorGrey2,
            height: 1.5,
          ),
        ],
      ),
    );
  }

  Widget _deferralRow(DeferralCount item) {
    return Container(
      margin: const EdgeInsets.only(bottom: 8),
      child: card(
        padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 13),
        child: Row(
          children: [
            Expanded(
              child: text(item.title, 13, TextType.Regular,
                  color: colorPrimaryDark,
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis),
            ),
            pill("${item.count}×", colorStandingGrounded,
                colorStandingGroundedBg, textSize: 9),
          ],
        ),
      ),
    );
  }

  /// Your estimates are wrong, and this is by how much.
  Widget _estimationRow(MapEntry<String, double> entry) {
    return Container(
      margin: const EdgeInsets.only(bottom: 8),
      child: card(
        padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 13),
        child: Row(
          children: [
            Expanded(
              child: text(entry.key, 13, TextType.Regular,
                  color: colorPrimaryDark),
            ),
            text("${entry.value.toStringAsFixed(1)}×", 15, TextType.Bold,
                color: entry.value > 1.4 ? colorStandingGrounded : colorGrey2),
          ],
        ),
      ),
    );
  }

  Widget _trainingCard() {
    return card(
      child: Row(
        children: [
          Expanded(
            child: labelled(
              "Adherence",
              "${(_report.trainingAdherence * 100).round()}%",
              valueSize: 26,
              valueType: TextType.Light,
            ),
          ),
          Expanded(
            child: labelled(
              "Integrity",
              "${(_report.programIntegrity * 100).round()}%",
              valueSize: 26,
              valueType: TextType.Light,
              valueColor: _report.programIntegrity < 0.7
                  ? colorStandingGrounded
                  : colorPrimaryDark,
            ),
          ),
        ],
      ),
    );
  }

  @override
  void onReportLoaded(ReportCard report) {
    setState(() {
      _report = report;
    });
  }
}
