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

import '../about/external/data/Commitment.dart';
import '../about/internal/application/CommitmentClass.dart';
import '../about/internal/application/Standing.dart';
import 'Colors.dart';

/// Formatting and small shared derivations. Anything a screen would otherwise
/// inline twice belongs here.

/// "Mon 06:00–08:00" — the window, which is the whole point.
String formatWindow(Commitment commitment) {
  if (commitment.dueStart == null || commitment.dueEnd == null) {
    return "No window set";
  }

  final DateFormat day = DateFormat('EEE');
  final DateFormat time = DateFormat('HH:mm');

  final String startDay = day.format(commitment.dueStart!);
  final String startTime = time.format(commitment.dueStart!);
  final String endTime = time.format(commitment.dueEnd!);

  final bool sameDay = commitment.dueStart!.day == commitment.dueEnd!.day &&
      commitment.dueStart!.month == commitment.dueEnd!.month;

  if (sameDay) {
    return "$startDay $startTime–$endTime";
  }

  return "$startDay $startTime – ${day.format(commitment.dueEnd!)} $endTime";
}

String formatDate(DateTime? value) {
  if (value == null) {
    return "";
  }
  return DateFormat('d MMM yyyy').format(value);
}

String formatDateTime(DateTime? value) {
  if (value == null) {
    return "";
  }
  return DateFormat('d MMM, HH:mm').format(value);
}

/// "3h 20m" from raw minutes.
String formatMinutes(num minutes) {
  final int total = minutes.round();
  if (total < 60) {
    return "${total}m";
  }
  final int hours = total ~/ 60;
  final int remainder = total % 60;
  if (remainder == 0) {
    return "${hours}h";
  }
  return "${hours}h ${remainder}m";
}

/// "12:04" from raw seconds — for the proof timer and rest clocks.
String formatClock(int seconds) {
  final int safe = seconds < 0 ? 0 : seconds;
  final int minutes = safe ~/ 60;
  final int remainder = safe % 60;
  return "${minutes.toString().padLeft(2, '0')}:${remainder.toString().padLeft(2, '0')}";
}

/// Debt is shown to one decimal — precise enough to move visibly when you
/// clear something, coarse enough not to look like a lie.
String formatDebt(double debt) {
  return debt.toStringAsFixed(1);
}

/// "2 days overdue", "Due in 40m", "Window closes in 3h".
String overdueLabel(Commitment commitment) {
  if (commitment.dueEnd == null) {
    return "";
  }

  final Duration difference = DateTime.now().difference(commitment.dueEnd!);

  if (difference.isNegative) {
    final Duration remaining = difference.abs();
    if (remaining.inHours < 1) {
      return "Closes in ${remaining.inMinutes}m";
    }
    if (remaining.inDays < 1) {
      return "Closes in ${remaining.inHours}h";
    }
    return "Closes in ${remaining.inDays}d";
  }

  if (difference.inHours < 1) {
    return "${difference.inMinutes}m overdue";
  }
  if (difference.inDays < 1) {
    return "${difference.inHours}h overdue";
  }
  if (difference.inDays == 1) {
    return "1 day overdue";
  }
  return "${difference.inDays} days overdue";
}

Color standingColor(Standing standing) {
  switch (standing) {
    case Standing.Good:
      return colorStandingGood;
    case Standing.Warned:
      return colorStandingWarned;
    case Standing.Grounded:
      return colorStandingGrounded;
    case Standing.Lockdown:
      return colorStandingLockdown;
  }
}

Color standingBackground(Standing standing) {
  switch (standing) {
    case Standing.Good:
      return colorStandingGoodBg;
    case Standing.Warned:
      return colorStandingWarnedBg;
    case Standing.Grounded:
      return colorStandingGroundedBg;
    case Standing.Lockdown:
      return colorStandingLockdownBg;
  }
}

Color classColor(CommitmentClass value) {
  switch (value) {
    case CommitmentClass.NonNegotiable:
      return colorClassNonNegotiable;
    case CommitmentClass.Standard:
      return colorClassStandard;
    case CommitmentClass.Elective:
      return colorClassElective;
  }
}

Color classBackground(CommitmentClass value) {
  switch (value) {
    case CommitmentClass.NonNegotiable:
      return colorClassNonNegotiableBg;
    case CommitmentClass.Standard:
      return colorClassStandardBg;
    case CommitmentClass.Elective:
      return colorClassElectiveBg;
  }
}

/// The weekday name for a 1..7 index.
String weekdayName(int weekday) {
  const List<String> names = <String>[
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday",
  ];
  if (weekday < 1 || weekday > 7) {
    return "";
  }
  return names[weekday - 1];
}

/// "7pm" for an hour-of-day index.
String hourLabel(int hour) {
  if (hour < 0) {
    return "";
  }
  if (hour == 0) {
    return "midnight";
  }
  if (hour < 12) {
    return "${hour}am";
  }
  if (hour == 12) {
    return "noon";
  }
  return "${hour - 12}pm";
}
