#!/usr/bin/env bash

set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=../main.sh
source "$ROOT_DIR/main.sh"

TEST_TMP="$(mktemp -d "${TMPDIR:-/tmp}/blackout-cli-tests.XXXXXX")"
trap 'rm -rf -- "$TEST_TMP"' EXIT

assert_equal() {
  local expected="$1"
  local actual="$2"
  local message="$3"

  if [[ "$expected" != "$actual" ]]; then
    printf 'FAIL: %s\nExpected: %s\nActual:   %s\n' "$message" "$expected" "$actual" >&2
    exit 1
  fi
}

assert_contains() {
  local text="$1"
  local expected="$2"
  local message="$3"

  if [[ "$text" != *"$expected"* ]]; then
    printf 'FAIL: %s\nMissing: %s\n' "$message" "$expected" >&2
    exit 1
  fi
}

FIXTURE="$TEST_TMP/outages.json"
cat >"$FIXTURE" <<'JSON'
{
  "schema_version": 1,
  "updated_at": "2026-07-18T16:00:00+03:30",
  "bills": {
    "222": {
      "events": {
        "5": {
          "status": "active",
          "snapshot": {
            "outage_number": "5",
            "outage_date": "1405/04/28",
            "start_time": "09:00",
            "stop_time": "11:00",
            "address": "Future planned address",
            "reason": "Maintenance",
            "is_planned": true
          }
        }
      }
    },
    "111": {
      "events": {
        "1": {
          "status": "active",
          "snapshot": {
            "outage_number": "1",
            "outage_date": "1405/04/27",
            "start_time": "16:00",
            "stop_time": "18:00",
            "address": "Current address",
            "reason": "Load management",
            "is_planned": true
          }
        },
        "2": {
          "status": "active",
          "snapshot": {
            "outage_number": "2",
            "outage_date": "1405/04/27",
            "start_time": "18:00",
            "stop_time": "20:00",
            "address": "Emergency address",
            "reason": "Emergency load management",
            "is_planned": false
          }
        },
        "3": {
          "status": "cancelled",
          "snapshot": {
            "outage_number": "3",
            "outage_date": "1405/04/27",
            "start_time": "19:00",
            "stop_time": "21:00",
            "address": "Cancelled address",
            "reason": "Cancelled maintenance",
            "is_planned": true
          }
        },
        "4": {
          "status": "active",
          "snapshot": {
            "outage_number": "4",
            "outage_date": "1405/04/27",
            "start_time": "10:00",
            "stop_time": "11:00",
            "address": "Expired address",
            "reason": "Old event",
            "is_planned": true
          }
        }
      }
    }
  }
}
JSON

assert_equal "2026-07-18" "$(jalali_to_gregorian "1405/04/27")" \
  "Jalali dates should convert to Gregorian dates"

read -r cross_start cross_stop < <(event_epochs "1405/04/27" "23:00" "01:00")
assert_equal "7200" "$((cross_stop - cross_start))" \
  "cross-midnight outages should end on the following day"

assert_equal "01 : 01 : 01" "$(banner_duration 3661)" \
  "countdowns should include hours, minutes, and seconds"
assert_equal "49 : 30 : 00" "$(banner_duration 178200)" \
  "countdowns should use total hours beyond one day"
FONT_OUTPUT="$(print_large_countdown "00 : 00 : 00" 150)"
assert_contains "$FONT_OUTPUT" ',a8888a,' \
  "the countdown should consistently use the univers-style font"

if ! validate_state "$FIXTURE"; then
  printf 'FAIL: valid fixture was rejected\n' >&2
  exit 1
fi

NOW_EPOCH="$(TZ=Asia/Tehran date -d '2026-07-18 17:00:00' +%s)"
build_schedule "$FIXTURE" "$NOW_EPOCH"
assert_equal "3" "${#SCHEDULE[@]}" \
  "only active current and future events should be scheduled"
assert_equal "ONGOING" "${HERO%%$'\t'*}" \
  "an ongoing outage should take the hero position"
assert_contains "${SCHEDULE[0]}" '"outage_number":"1"' \
  "ongoing events should sort first"
assert_contains "${SCHEDULE[1]}" '"outage_number":"2"' \
  "the nearest future event should sort second"
assert_contains "${SCHEDULE[2]}" '"outage_number":"5"' \
  "later events should remain in the schedule"

build_schedule "$FIXTURE" "$NOW_EPOCH" "222"
assert_equal "3" "${#SCHEDULE[@]}" \
  "selecting a countdown bill should not filter the schedule"
assert_equal "UPCOMING" "${HERO%%$'\t'*}" \
  "the countdown should ignore another bill's ongoing outage"
assert_contains "$HERO" '"bill_id":"222"' \
  "the countdown should use only the selected bill"
SELECTED_OUTPUT="$(NO_COLOR=1 COLUMNS=80 render_dashboard "$NOW_EPOCH" 80 "222")"
assert_contains "$SELECTED_OUTPUT" "COUNTDOWN FOR BILL 222" \
  "the selected countdown bill should be labeled"
assert_contains "$SELECTED_OUTPUT" "OUTAGE SCHEDULE (3)" \
  "the selected countdown bill should not hide other bills from the list"

build_schedule "$FIXTURE" "$NOW_EPOCH" "333"
assert_equal "" "$HERO" \
  "a bill without upcoming outages should not borrow another bill's countdown"
NO_HERO_OUTPUT="$(NO_COLOR=1 COLUMNS=80 render_dashboard "$NOW_EPOCH" 80 "333")"
assert_contains "$NO_HERO_OUTPUT" "NO CURRENT OR UPCOMING OUTAGE" \
  "a selected bill without outages should have a clear countdown status"
assert_contains "$NO_HERO_OUTPUT" "OUTAGE SCHEDULE (3)" \
  "all bills should remain listed when the selected bill has no outage"

build_schedule "$FIXTURE" "$NOW_EPOCH"
OUTPUT="$(NO_COLOR=1 COLUMNS=80 render_dashboard "$NOW_EPOCH")"
if [[ "$OUTPUT" == *"POWER RETURNS IN"* || "$OUTPUT" == *"NEXT OUTAGE IN"* ]]; then
  printf 'FAIL: countdown output contains a redundant heading\n' >&2
  exit 1
fi
assert_contains "$OUTPUT" "PLANNED" \
  "planned events should be labeled"
assert_contains "$OUTPUT" "EMERGENCY" \
  "unplanned events should be labeled"
assert_contains "$OUTPUT" "OUTAGE SCHEDULE (3)" \
  "the dashboard should include every selected event"
if [[ "$OUTPUT" == *"Address"* || "$OUTPUT" == *"Reason"* \
  || "$OUTPUT" == *"Emergency address"* || "$OUTPUT" == *"Load management"* ]]; then
  printf 'FAIL: dashboard output exposes address or reason text\n' >&2
  exit 1
fi
if [[ "$OUTPUT" == *$'\033['* ]]; then
  printf 'FAIL: NO_COLOR output contains ANSI escapes\n' >&2
  exit 1
fi
WIDE_OUTPUT="$(NO_COLOR=1 COLUMNS=180 render_dashboard "$NOW_EPOCH")"
WIDE_TOP_LINE="${WIDE_OUTPUT%%$'\n'*}"
assert_equal "180" "${#WIDE_TOP_LINE}" \
  "the countdown divider should span the full terminal width"
WIDE_BOTTOM_LINE="${WIDE_OUTPUT##*$'\n'}"
assert_equal "180" "${#WIDE_BOTTOM_LINE}" \
  "the dashboard bottom divider should span the full terminal width"

FUTURE_NOW="$(TZ=Asia/Tehran date -d '2026-07-18 15:00:00' +%s)"
build_schedule "$FIXTURE" "$FUTURE_NOW"
assert_equal "UPCOMING" "${HERO%%$'\t'*}" \
  "the nearest future event should be the hero when none are ongoing"

EMPTY_NOW="$(TZ=Asia/Tehran date -d '2026-07-20 12:00:00' +%s)"
build_schedule "$FIXTURE" "$EMPTY_NOW"
assert_equal "0" "${#SCHEDULE[@]}" \
  "expired schedules should become empty"
EMPTY_OUTPUT="$(NO_COLOR=1 COLUMNS=60 render_dashboard "$EMPTY_NOW")"
assert_contains "$EMPTY_OUTPUT" "ALL CLEAR" \
  "an empty schedule should render the all-clear screen"
WIDE_EMPTY_OUTPUT="$(NO_COLOR=1 COLUMNS=180 render_dashboard "$EMPTY_NOW")"
WIDE_EMPTY_TOP_LINE="${WIDE_EMPTY_OUTPUT%%$'\n'*}"
WIDE_EMPTY_BOTTOM_LINE="${WIDE_EMPTY_OUTPUT##*$'\n'}"
assert_equal "180" "${#WIDE_EMPTY_TOP_LINE}" \
  "the all-clear top divider should span the full terminal width"
assert_equal "180" "${#WIDE_EMPTY_BOTTOM_LINE}" \
  "the all-clear bottom divider should span the full terminal width"

WIDE_UNAVAILABLE_OUTPUT="$(NO_COLOR=1 COLUMNS=80 render_unavailable 180)"
WIDE_UNAVAILABLE_TOP_LINE="${WIDE_UNAVAILABLE_OUTPUT%%$'\n'*}"
WIDE_UNAVAILABLE_BOTTOM_LINE="${WIDE_UNAVAILABLE_OUTPUT##*$'\n'}"
assert_equal "180" "${#WIDE_UNAVAILABLE_TOP_LINE}" \
  "the unavailable top divider should span the full terminal width"
assert_equal "180" "${#WIDE_UNAVAILABLE_BOTTOM_LINE}" \
  "the unavailable bottom divider should use the detected terminal width"

TERMINAL_ACTIVE=1
DRAW_OUTPUT="$(draw_frame $'short\nlonger')"
TERMINAL_ACTIVE=0
assert_contains "$DRAW_OUTPUT" $'short\033[K\nlonger\033[K' \
  "interactive redraws should erase old content from every line"

MALFORMED="$TEST_TMP/malformed.json"
printf '{"schema_version": 999, "bills": {}}\n' >"$MALFORMED"
if validate_state "$MALFORMED"; then
  printf 'FAIL: unsupported schema was accepted\n' >&2
  exit 1
fi

if (
  curl() { return 22; }
  fetch_state "$TEST_TMP/download.json" "123"
); then
  printf 'FAIL: download failure was reported as success\n' >&2
  exit 1
fi

if main --bill-id invalid >/dev/null 2>&1; then
  printf 'FAIL: a non-decimal countdown bill ID was accepted\n' >&2
  exit 1
fi

printf 'Bash CLI tests passed\n'
