#!/usr/bin/env bash
set -euo pipefail

LICENSE_DIR="/etc/saikyo/license"
PUBKEY_FILE="/usr/share/saikyo-os/license/saikyo-license-pub.pem"
PUBKEY_ED25519_FILE="/usr/share/saikyo-os/license/saikyo-license-ed25519-pub.pem"
LICENSE_JSON="${LICENSE_DIR}/license.json"
LICENSE_SIG="${LICENSE_DIR}/license.sig"
TRIAL_START_FILE="${LICENSE_DIR}/trial_start"
TRIAL_DAYS=7

require_jq() {
  if ! command -v jq >/dev/null 2>&1; then
    echo "ERROR: jq is required" >&2
    exit 1
  fi
}

usage() {
  echo "Usage: saikyo-license <command> [args]" >&2
  echo "Commands:" >&2
  echo "  install <license.json> <license.sig>" >&2
  echo "  install-code <response-code>" >&2
  echo "  activate --token <token> [--server <url>]" >&2
  echo "  renew --token <token> [--server <url>]" >&2
  echo "  verify" >&2
  echo "  status" >&2
  exit 2
}

require_root() {
  if [[ "$(id -u)" -ne 0 ]]; then
    echo "ERROR: must be run as root" >&2
    exit 1
  fi
}

verify_pair() {
  if [[ ! -f "${PUBKEY_FILE}" && ! -f "${PUBKEY_ED25519_FILE}" ]]; then
    echo "ERROR: public keys not found in /usr/share/saikyo-os/license" >&2
    exit 1
  fi
  if [[ ! -f "${LICENSE_JSON}" || ! -f "${LICENSE_SIG}" ]]; then
    if [[ -f "${TRIAL_START_FILE}" ]]; then
      local start now end
      start=$(cat "${TRIAL_START_FILE}" 2>/dev/null | tr -d '\r\n' | head -c 32)
      now=$(date -u +%s 2>/dev/null || echo "")
      if [[ -n "${start}" && -n "${now}" && "${start}" =~ ^[0-9]+$ ]]; then
        end=$(( start + TRIAL_DAYS*86400 ))
        if [[ "${now}" -le "${end}" ]]; then
          echo "VALID"
          return 0
        fi
      fi
    fi
    echo "INVALID"
    return 1
  fi

  require_jq

  # Verify signature over raw JSON bytes.
  # New licenses: Ed25519 (pkeyutl -verify -rawin).
  # Legacy licenses: RSA (dgst -sha256 -verify).
  if [[ -f "${PUBKEY_ED25519_FILE}" ]]; then
    if openssl pkeyutl -verify -pubin -inkey "${PUBKEY_ED25519_FILE}" -rawin -in "${LICENSE_JSON}" -sigfile "${LICENSE_SIG}" >/dev/null 2>&1; then
      :
    else
      if [[ -f "${PUBKEY_FILE}" ]]; then
        if ! openssl dgst -sha256 -verify "${PUBKEY_FILE}" -signature "${LICENSE_SIG}" "${LICENSE_JSON}" >/dev/null 2>&1; then
          echo "INVALID"
          return 1
        fi
      else
        echo "INVALID"
        return 1
      fi
    fi
  else
    if ! openssl dgst -sha256 -verify "${PUBKEY_FILE}" -signature "${LICENSE_SIG}" "${LICENSE_JSON}" >/dev/null 2>&1; then
      echo "INVALID"
      return 1
    fi
  fi

  local lic_machine_id lic_valid_until
  lic_machine_id=$(jq -r '.machine_id // empty' "${LICENSE_JSON}" 2>/dev/null || true)
  lic_valid_until=$(jq -r '.valid_until // empty' "${LICENSE_JSON}" 2>/dev/null || true)

  if [[ -z "${lic_machine_id}" || -z "${lic_valid_until}" ]]; then
    echo "INVALID"
    return 1
  fi

  local current_machine_id
  current_machine_id=""
  if [[ -f /etc/machine-id ]]; then
    current_machine_id=$(cat /etc/machine-id 2>/dev/null || true)
  fi
  if [[ -z "${current_machine_id}" || "${lic_machine_id}" != "${current_machine_id}" ]]; then
    echo "INVALID"
    return 1
  fi

  local now exp
  now=$(date -u +%s)
  exp=$(date -u -d "${lic_valid_until}" +%s 2>/dev/null || echo "")
  if [[ -z "${exp}" || "${now}" -gt "${exp}" ]]; then
    echo "INVALID"
    return 1
  fi

  echo "VALID"
  return 0
}

cmd_install() {
  require_root
  local src_json="${1:-}"
  local src_sig="${2:-}"
  [[ -n "${src_json}" && -n "${src_sig}" ]] || usage
  [[ -f "${src_json}" ]] || { echo "ERROR: file not found: ${src_json}" >&2; exit 1; }
  [[ -f "${src_sig}" ]] || { echo "ERROR: file not found: ${src_sig}" >&2; exit 1; }

  require_jq

  local lic_machine_id
  lic_machine_id=$(jq -r '.machine_id // empty' "${src_json}" 2>/dev/null || true)
  if [[ -z "${lic_machine_id}" ]]; then
    echo "ERROR: license.json missing required field: machine_id" >&2
    exit 1
  fi

  local current_machine_id
  current_machine_id=""
  if [[ -f /etc/machine-id ]]; then
    current_machine_id=$(cat /etc/machine-id 2>/dev/null || true)
  fi
  if [[ -z "${current_machine_id}" ]]; then
    echo "ERROR: cannot read /etc/machine-id" >&2
    exit 1
  fi
  if [[ "${lic_machine_id}" != "${current_machine_id}" ]]; then
    echo "ERROR: machine-id mismatch" >&2
    echo " expected=${lic_machine_id}" >&2
    echo " actual=${current_machine_id}" >&2
    exit 1
  fi

  mkdir -p "${LICENSE_DIR}"
  chmod 0755 "${LICENSE_DIR}"
  install -m 0644 "${src_json}" "${LICENSE_JSON}"
  install -m 0644 "${src_sig}" "${LICENSE_SIG}"

  verify_pair >/dev/null
  echo "OK"
}

cmd_install_code() {
  require_root
  require_jq

  local rc="${1:-}"
  [[ -n "${rc}" ]] || usage
  rc=$(printf '%s' "$rc" | tr -d '\r\n\t ' | tr -d '-' | head -c 20000)

  local td lic_json lic_sig
  td=$(mktemp -d)
  lic_json="${td}/license.json"
  lic_sig="${td}/license.sig"

  if printf '%s' "$rc" | grep -q '^SAI-RC:'; then
    if ! command -v base32 >/dev/null 2>&1; then
      echo "ERROR: base32 is required" >&2
      rm -rf "${td}" || true
      exit 1
    fi
    local body ppart spart ppad spad
    body=${rc#SAI-RC:}
    ppart=${body%%.*}
    spart=${body#*.}
    if [[ -z "${ppart}" || -z "${spart}" || "${ppart}" == "${body}" ]]; then
      echo "ERROR: invalid SAI-RC format" >&2
      rm -rf "${td}" || true
      exit 1
    fi
    ppad=$(( (8 - (${#ppart} % 8)) % 8 ))
    spad=$(( (8 - (${#spart} % 8)) % 8 ))
    if [[ "$ppad" -gt 0 ]]; then ppart="${ppart}$(printf '%*s' "$ppad" '' | tr ' ' '=')"; fi
    if [[ "$spad" -gt 0 ]]; then spart="${spart}$(printf '%*s' "$spad" '' | tr ' ' '=')"; fi
    printf '%s' "$ppart" | base32 -d >"${lic_json}" 2>/dev/null || true
    printf '%s' "$spart" | base32 -d >"${lic_sig}" 2>/dev/null || true
  elif printf '%s' "$rc" | grep -q '^SAI-RESP2:'; then
    local body jpart spart jb64 sb64 jpad spad
    body=${rc#SAI-RESP2:}
    jpart=${body%%.*}
    spart=${body#*.}
    if [[ -z "${jpart}" || -z "${spart}" || "${jpart}" == "${body}" ]]; then
      echo "ERROR: invalid SAI-RESP2 format" >&2
      rm -rf "${td}" || true
      exit 1
    fi
    jb64=$(printf '%s' "$jpart" | tr '_-' '/+')
    sb64=$(printf '%s' "$spart" | tr '_-' '/+')
    jpad=$(( (4 - (${#jb64} % 4)) % 4 ))
    spad=$(( (4 - (${#sb64} % 4)) % 4 ))
    if [[ "$jpad" -eq 1 ]]; then jb64="${jb64}="; elif [[ "$jpad" -eq 2 ]]; then jb64="${jb64}=="; elif [[ "$jpad" -eq 3 ]]; then jb64="${jb64}==="; fi
    if [[ "$spad" -eq 1 ]]; then sb64="${sb64}="; elif [[ "$spad" -eq 2 ]]; then sb64="${sb64}=="; elif [[ "$spad" -eq 3 ]]; then sb64="${sb64}==="; fi
    printf '%s' "$jb64" | base64 -d >"${lic_json}" 2>/dev/null || true
    printf '%s' "$sb64" | base64 -d >"${lic_sig}" 2>/dev/null || true
  elif printf '%s' "$rc" | grep -q '^SAI-RESP:'; then
    local b64u payload lic_json_b64 lic_sig_b64 pad
    b64u=${rc#SAI-RESP:}
    b64u=$(printf '%s' "$b64u" | tr '_-' '/+')
    pad=$(( (4 - (${#b64u} % 4)) % 4 ))
    if [[ "$pad" -eq 1 ]]; then b64u="${b64u}="; elif [[ "$pad" -eq 2 ]]; then b64u="${b64u}=="; elif [[ "$pad" -eq 3 ]]; then b64u="${b64u}==="; fi
    payload=$(printf '%s' "$b64u" | base64 -d 2>/dev/null || true)
    lic_json_b64=$(printf '%s' "$payload" | sed -n 's/.*"license_json_b64":"\([^"]*\)".*/\1/p' | head -c 20000)
    lic_sig_b64=$(printf '%s' "$payload" | sed -n 's/.*"license_sig_b64":"\([^"]*\)".*/\1/p' | head -c 20000)
    if [[ -z "${lic_json_b64}" || -z "${lic_sig_b64}" ]]; then
      echo "ERROR: invalid SAI-RESP payload" >&2
      rm -rf "${td}" || true
      exit 1
    fi
    printf '%s' "$lic_json_b64" | base64 -d >"${lic_json}" 2>/dev/null || true
    printf '%s' "$lic_sig_b64" | base64 -d >"${lic_sig}" 2>/dev/null || true
  else
    echo "ERROR: unsupported response-code format" >&2
    rm -rf "${td}" || true
    exit 1
  fi

  if [[ ! -s "${lic_json}" || ! -s "${lic_sig}" ]]; then
    echo "ERROR: failed to decode response-code" >&2
    rm -rf "${td}" || true
    exit 1
  fi

  cmd_install "${lic_json}" "${lic_sig}"
  rm -rf "${td}" || true
}

cmd_verify() {
  verify_pair
}

cmd_activate() {
  require_root
  require_jq

  local server="https://saikyo-os.ru/license"
  local token=""

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --server)
        server="${2:-}"; shift 2 || true
        ;;
      --token)
        token="${2:-}"; shift 2 || true
        ;;
      -h|--help)
        usage
        ;;
      *)
        echo "ERROR: unknown option: $1" >&2
        usage
        ;;
    esac
  done

  if [[ -z "${token}" ]]; then
    echo "ERROR: --token is required" >&2
    exit 1
  fi
  if [[ -z "${server}" ]]; then
    echo "ERROR: --server is empty" >&2
    exit 1
  fi
  if ! command -v curl >/dev/null 2>&1; then
    echo "ERROR: curl is required for online activation" >&2
    exit 1
  fi
  if [[ ! -r /etc/ssl/certs/ca-certificates.crt ]]; then
    echo "ERROR: CA bundle not found: /etc/ssl/certs/ca-certificates.crt" >&2
    exit 1
  fi

  local server_host
  server_host=$(printf '%s' "${server}" | sed -n 's#^https\?://\([^/]*\).*#\1#p' | head -n 1)
  if [[ -n "${server_host}" ]] && command -v getent >/dev/null 2>&1; then
    if ! getent ahosts "${server_host}" >/dev/null 2>&1; then
      echo "ERROR: cannot resolve server host: ${server_host}" >&2
      exit 1
    fi
  fi

  local mid
  mid=$(cat /etc/machine-id 2>/dev/null || true)
  if [[ -z "${mid}" ]]; then
    echo "ERROR: cannot read /etc/machine-id" >&2
    exit 1
  fi

  local req tmpdir resp_json lic_json_b64 lic_sig_b64
  req=$(jq -n --arg token "${token}" --arg machine_id "${mid}" --arg hostname "$(hostname 2>/dev/null || true)" '{token:$token, machine_id:$machine_id, hostname:$hostname}')

  tmpdir=$(mktemp -d)
  trap 'rm -rf "${tmpdir}" 2>/dev/null || true' RETURN

  resp_json="${tmpdir}/response.json"
  resp_err="${tmpdir}/curl.stderr"
  req_file="${tmpdir}/request.json"
  http_code=""

  printf '%s' "${req}" > "${req_file}"

  http_code=$(curl -sS \
    --connect-timeout 10 \
    --max-time 30 \
    --retry 3 \
    --retry-delay 1 \
    --retry-connrefused \
    --retry-all-errors \
    -H 'Content-Type: application/json' \
    -X POST \
    --data-binary "@${req_file}" \
    "${server%/}/v1/activate" \
    -o "${resp_json}" \
    -w '%{http_code}' \
    2>"${resp_err}" || true)

  if [[ "${http_code}" != 2* ]]; then
    echo "ERROR: activation request failed (http_code=${http_code:-unknown})" >&2
    if [[ -s "${resp_err}" ]]; then
      sed -n '1,120p' "${resp_err}" >&2 || true
    fi
    if [[ -s "${resp_json}" ]]; then
      sed -n '1,200p' "${resp_json}" >&2 || true
    fi
    exit 1
  fi

  lic_json_b64=$(jq -r '.license_json_b64 // empty' "${resp_json}" 2>/dev/null || true)
  lic_sig_b64=$(jq -r '.license_sig_b64 // empty' "${resp_json}" 2>/dev/null || true)

  if [[ -z "${lic_json_b64}" || -z "${lic_sig_b64}" ]]; then
    echo "ERROR: invalid response from license server" >&2
    cat "${resp_json}" >&2 || true
    exit 1
  fi

  local lic_json_file lic_sig_file
  lic_json_file="${tmpdir}/license.json"
  lic_sig_file="${tmpdir}/license.sig"

  printf '%s' "${lic_json_b64}" | base64 -d > "${lic_json_file}"
  printf '%s' "${lic_sig_b64}" | base64 -d > "${lic_sig_file}"

  cmd_install "${lic_json_file}" "${lic_sig_file}"
}

cmd_renew() {
  cmd_activate "$@"
}

cmd_status() {
  if [[ ! -f "${LICENSE_JSON}" ]]; then
    if [[ -f "${TRIAL_START_FILE}" ]]; then
      local start now end rem
      start=$(cat "${TRIAL_START_FILE}" 2>/dev/null | tr -d '\r\n' | head -c 32)
      now=$(date -u +%s 2>/dev/null || echo "")
      if [[ -n "${start}" && -n "${now}" && "${start}" =~ ^[0-9]+$ ]]; then
        end=$(( start + TRIAL_DAYS*86400 ))
        if [[ "${now}" -le "${end}" ]]; then
          rem=$(( end - now ))
          echo "status=trial"
          echo "trial_days=${TRIAL_DAYS}"
          echo "trial_remaining_seconds=${rem}"
          exit 0
        fi
      fi
    fi
    echo "status=missing"
    exit 0
  fi

  local sig_status
  if sig_status=$(verify_pair 2>/dev/null); then
    echo "signature=${sig_status,,}"
  else
    echo "signature=invalid"
  fi

  require_jq

  local org_id org_name valid_until tier machine_id
  org_id=$(jq -r '.org_id // empty' "${LICENSE_JSON}" 2>/dev/null || true)
  org_name=$(jq -r '.org_name // empty' "${LICENSE_JSON}" 2>/dev/null || true)
  valid_until=$(jq -r '.valid_until // empty' "${LICENSE_JSON}" 2>/dev/null || true)
  tier=$(jq -r '.tier // empty' "${LICENSE_JSON}" 2>/dev/null || true)
  machine_id=$(jq -r '.machine_id // empty' "${LICENSE_JSON}" 2>/dev/null || true)

  [[ -n "${org_id}" ]] && echo "org_id=${org_id}"
  [[ -n "${org_name}" ]] && echo "org_name=${org_name}"
  [[ -n "${tier}" ]] && echo "tier=${tier}"
  [[ -n "${machine_id}" ]] && echo "machine_id=${machine_id}"
  [[ -n "${valid_until}" ]] && echo "valid_until=${valid_until}"

  if [[ -n "${valid_until}" ]]; then
    local now exp
    now=$(date -u +%s)
    exp=$(date -u -d "${valid_until}" +%s 2>/dev/null || echo "")
    if [[ -n "${exp}" && "${now}" -gt "${exp}" ]]; then
      echo "expired=yes"
    else
      echo "expired=no"
    fi
  fi
}

main() {
  local cmd="${1:-}"
  shift || true
  case "${cmd}" in
    install)
      cmd_install "$@"
      ;;
    install-code)
      cmd_install_code "$@"
      ;;
    activate)
      cmd_activate "$@"
      ;;
    renew)
      cmd_renew "$@"
      ;;
    verify) cmd_verify;;
    status) cmd_status;;
    -h|--help|help|"") usage;;
    *) usage;;
  esac
}

main "$@"
