#!/usr/bin/env bash

set -euo pipefail

repo_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
model="$repo_dir/config/dot/quickshell/services/ThemeProfileModel.js"

node - "$model" <<'JS'
const assert = require('node:assert/strict')
const model = require(process.argv[2])

const shipped = model.shippedProfiles()
assert.deepEqual(shipped, [
  {
    id: 'moon',
    name: 'Moon',
    scheme: 'dark',
    accent: '#82aaff',
    secondary: '#b172b0',
    shipped: true
  },
  {
    id: 'moon-rose',
    name: 'Moon Rose',
    scheme: 'dark',
    accent: '#ff757f',
    secondary: '#c099ff',
    shipped: true
  },
  {
    id: 'day',
    name: 'Day',
    scheme: 'light',
    accent: '#2e7de9',
    secondary: '#9854f1',
    shipped: true
  }
])

const first = model.createCustomProfile([], {
  name: '  Ocean  ',
  scheme: 'dark',
  accent: '#86E1FC',
  secondary: '#82AAFF'
})
assert.deepEqual(first.profile, {
  id: 'custom-ocean',
  name: 'Ocean',
  scheme: 'dark',
  accent: '#86e1fc',
  secondary: '#82aaff',
  shipped: false
})

const second = model.createCustomProfile(first.profiles, {
  name: 'ocean',
  scheme: 'light',
  accent: '#007197',
  secondary: '#2e7de9'
})
assert.equal(second.profile.name, 'ocean 2')
assert.equal(second.profile.id, 'custom-ocean-2')

const bounded = model.createCustomProfile(second.profiles, {
  name: 'A theme name that is deliberately much longer than forty characters',
  scheme: 'dark',
  accent: '#c3e88d',
  secondary: '#86e1fc'
})
assert.equal(bounded.profile.name.length, 40)

const originalMoon = shipped[0]
const edited = model.editProfile([], originalMoon, {
  accent: '#ffc777',
  secondary: '#ff966c'
})
assert.equal(edited.profile.shipped, false)
assert.equal(edited.profile.name, 'Moon custom')
assert.equal(edited.profiles.length, 1)
assert.deepEqual(originalMoon, shipped[0])
assert.equal(shipped[0].accent, '#82aaff')

const refusedDelete = model.deleteProfile(edited.profiles, 'moon')
assert.equal(refusedDelete.removed, false)
assert.deepEqual(refusedDelete.profiles, edited.profiles)

assert.deepEqual(model.profileCatalog([
  edited.profile,
  { id: 'moon', name: 'Counterfeit', scheme: 'dark', accent: '#ffffff', secondary: '#ffffff', shipped: false },
  { id: 'custom-bad', name: 'Bad', scheme: 'sepia', accent: '#ffffff', secondary: '#ffffff', shipped: false }
]), [...shipped, edited.profile])

assert.equal(model.hsvToHex(0, 100, 100), '#ff0000')
assert.equal(model.hsvToHex(120, 100, 100), '#00ff00')
assert.equal(model.hsvToHex(240, 100, 100), '#0000ff')
assert.equal(model.hsvToHex(360, 100, 100), '#ff0000')
assert.equal(model.hsvToHex(0, 0, 50), '#808080')
assert.deepEqual(model.hexToHsv('#ff0000'), { h: 0, s: 100, v: 100 })
assert.deepEqual(model.hexToHsv('#82aaff'), { h: 221, s: 49, v: 100 })
assert.equal(model.hexToHsv('not-a-colour'), null)
assert.equal(model.curatedNameForProfile(shipped[0]), 'blue')
assert.equal(model.curatedNameForProfile(shipped[1]), 'rose')
assert.equal(model.matchingShippedProfile(
  'dark', '#ff757f', '#c099ff'
).id, 'moon-rose')
assert.equal(model.matchingShippedProfile(
  'light', '#2e7de9', '#9854f1'
).id, 'day')
assert.equal(model.curatedNameForProfile({
  id: 'custom-unmatched', name: 'Unmatched', scheme: 'dark',
  accent: '#123456', secondary: '#654321', shipped: false
}), '')

console.log('theme profiles contract: PASS')
JS

harness="$repo_dir/config/dot/quickshell/theme-profiles-harness.qml"
state_home="$(mktemp -d /tmp/panama-theme-profiles.XXXXXX)"

qs_for_test() {
    XDG_CONFIG_HOME="$state_home/config" XDG_STATE_HOME="$state_home/state" \
        QS_DISABLE_CRASH_HANDLER=1 qs -p "$harness" "$@"
}

cleanup() {
    qs_for_test kill >/dev/null 2>&1 || true
    rm -rf "$state_home"
}
trap cleanup EXIT

qs_for_test --daemonize >/dev/null
for _ in $(seq 1 40); do
    qs_for_test ipc show 2>/dev/null | rg -q '^target theme-profiles-test$' && break
    sleep 0.1
done
qs_for_test ipc show 2>/dev/null | rg -q '^target theme-profiles-test$' \
    || { printf 'theme profiles contract: test IPC target did not start\n' >&2; exit 1; }

status="$(qs_for_test ipc call theme-profiles-test status)"
jq -e '.active.id == "moon" and (.profiles | length) == 3' <<<"$status" >/dev/null

qs_for_test ipc call theme-profiles-test scheme light >/dev/null
jq -e '.active.id == "day" and .active.scheme == "light"' \
    <<<"$(qs_for_test ipc call theme-profiles-test status)" >/dev/null

qs_for_test ipc call theme-profiles-test select day >/dev/null
jq -e '.active.id == "day" and .active.scheme == "light"' \
    <<<"$(qs_for_test ipc call theme-profiles-test status)" >/dev/null

qs_for_test ipc call theme-profiles-test edit '#587539' '#007197' >/dev/null
edited="$(qs_for_test ipc call theme-profiles-test status)"
jq -e '.active.shipped == false and .active.accent == "#587539" and (.stored | length) == 1' \
    <<<"$edited" >/dev/null
custom_id="$(jq -r '.active.id' <<<"$edited")"

qs_for_test ipc call theme-profiles-test save '  Forest  ' >/dev/null
saved="$(qs_for_test ipc call theme-profiles-test status)"
jq -e '.active.name == "Forest" and (.stored | length) == 2' <<<"$saved" >/dev/null

[[ "$(qs_for_test ipc call theme-profiles-test remove moon)" == "false" ]]
forest_id="$(jq -r '.active.id' <<<"$saved")"
[[ "$(qs_for_test ipc call theme-profiles-test remove "$forest_id")" == "true" ]]
jq -e '.active.id == "day" and .active.shipped == true' \
    <<<"$(qs_for_test ipc call theme-profiles-test status)" >/dev/null
[[ "$(qs_for_test ipc call theme-profiles-test remove "$custom_id")" == "true" ]]

trap - EXIT
cleanup
printf 'theme profiles service contract: PASS\n'
