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

REPORTS_DIR="/var/lib/saikyo-av/reports"
LOG_DIR="/var/log/saikyo-av"
QUAR_DIR="/var/lib/saikyo-av/quarantine"

mkdir -p "${REPORTS_DIR}" "${LOG_DIR}" "${QUAR_DIR}" || true
chmod 0755 /var/lib/saikyo-av "${REPORTS_DIR}" "${LOG_DIR}" 2>/dev/null || true

cmd="${1:-}"
shift || true

utc_ts() {
  date -u +%Y-%m-%dT%H:%M:%SZ
}

write_report() {
  local id="$1"
  local summary="$2"
  local severity="$3"
  local outfile="${REPORTS_DIR}/${id}.json"
  local created
  created="$(utc_ts)"

  # shellcheck disable=SC2129
  {
    echo "{"
    echo "  \"created_utc\": \"${created}\","
    echo "  \"severity\": \"${severity}\","
    echo "  \"summary\": \"${summary}\","
    echo "  \"details\": {"
    echo "    \"action\": \"${cmd}\","
    echo "    \"argv\": \"$*\""
    echo "  },"
    echo "  \"artifacts\": {},"
    echo "  \"suggested_fixes\": []"
    echo "}"
  } > "${outfile}"

  echo "${outfile}"
}

run_to_file() {
  local out="$1"
  shift
  ("$@" 2>&1 || true) | sed -e 's/\r$//' > "${out}"
}

json_escape() {
  # Minimal JSON string escape (no unicode handling needed for our file paths)
  sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\t/\\t/g' -e 's/\r/\\r/g' -e 's/\n/\\n/g'
}

write_scan_report() {
  local id="$1"
  local summary="$2"
  local severity="$3"
  local log_file="$4"
  local detections_tsv="$5"
  local outfile="${REPORTS_DIR}/${id}.json"
  local created
  created="$(utc_ts)"

  local scanned_count infected_count
  scanned_count="$(grep -E '^Scanned files:' "${log_file}" 2>/dev/null | awk -F': ' '{print $2}' | tail -n 1 || true)"
  infected_count="$(grep -E '^Infected files:' "${log_file}" 2>/dev/null | awk -F': ' '{print $2}' | tail -n 1 || true)"
  scanned_count="${scanned_count:-0}"
  infected_count="${infected_count:-0}"

  {
    echo "{"
    echo "  \"created_utc\": \"${created}\"," 
    echo "  \"severity\": \"${severity}\"," 
    echo "  \"summary\": \"${summary}\"," 
    echo "  \"details\": {"
    echo "    \"action\": \"${cmd}\","
    echo "    \"argv\": \"$*\","
    echo "    \"scanned_files\": ${scanned_count},"
    echo "    \"infected_files\": ${infected_count},"
    echo "    \"detections\": ["

    if [[ -s "${detections_tsv}" ]]; then
      first=1
      while IFS=$'\t' read -r pth sig; do
        [[ -n "${pth}" ]] || continue
        pth_esc="$(printf '%s' "${pth}" | json_escape)"
        sig_esc="$(printf '%s' "${sig}" | json_escape)"
        if [[ "${first}" -eq 1 ]]; then
          first=0
        else
          echo ","
        fi
        printf '      {"path":"%s","name":"%s"}' "${pth_esc}" "${sig_esc}"
      done < "${detections_tsv}"
      echo
    fi

    echo "    ]"
    echo "  },"
    echo "  \"artifacts\": {"
    echo "    \"clamav_log\": \"${log_file}\","
    echo "    \"detections_tsv\": \"${detections_tsv}\""
    echo "  },"
    echo "  \"suggested_fixes\": ["
    echo "    {\"id\":\"quarantine\",\"title\":\"Quarantine infected file\",\"description\":\"Move selected file to local quarantine.\",\"requires_consent\":true},"
    echo "    {\"id\":\"delete\",\"title\":\"Delete infected file\",\"description\":\"Delete selected infected file (dangerous).\",\"requires_consent\":true}"
    echo "  ]"
    echo "}"
  } > "${outfile}"

  echo "${outfile}"
}

svc_is_enabled() {
  systemctl is-enabled saikyo-avd.timer 2>/dev/null || true
}

svc_is_active() {
  systemctl is-active saikyo-avd.timer 2>/dev/null || true
}

case "${cmd}" in
  health)
    echo "ok"
    ;;

  status-protection)
    echo "enabled=$(svc_is_enabled) active=$(svc_is_active)"
    ;;

  run-evidence)
    outdir="${REPORTS_DIR}/artifacts"
    mkdir -p "${outdir}" || true
    ts="$(date -u +%Y%m%dT%H%M%SZ)"
    evidence_out="${outdir}/saikyo-evidence-${ts}.log"

    if command -v saikyo-evidence >/dev/null 2>&1; then
      run_to_file "${evidence_out}" saikyo-evidence
    elif [ -x /usr/bin/saikyo-evidence ]; then
      run_to_file "${evidence_out}" /usr/bin/saikyo-evidence
    else
      echo "saikyo-evidence not found" > "${evidence_out}"
    fi

    rpt="$(write_report "evidence-${ts}" "Evidence report generated" "info" "${cmd}")"
    # Append artifacts into report JSON (minimal, without jq dependency).
    sed -i "s#\"artifacts\": {}#\"artifacts\": {\"evidence_log\": \"${evidence_out}\"}#" "${rpt}" || true
    echo "${rpt}"
    ;;

  scan)
    outdir="${REPORTS_DIR}/artifacts"
    mkdir -p "${outdir}" || true
    ts="$(date -u +%Y%m%dT%H%M%SZ)"
    log_file="${outdir}/clamav-scan-${ts}.log"
    det_tsv="${outdir}/clamav-detections-${ts}.tsv"

    if ! command -v clamscan >/dev/null 2>&1; then
      echo "clamscan not found (install clamav)" > "${log_file}"
      rpt="$(write_report "scan-${ts}" "ClamAV scan failed: clamscan not found" "warn" "${cmd}")"
      sed -i "s#\"artifacts\": {}#\"artifacts\": {\"clamav_log\": \"${log_file}\"}#" "${rpt}" || true
      echo "${rpt}"
      exit 1
    fi

    # Full scan of / with exclusions.
    # - exclude hidden paths (/.*/)
    # - exclude virtual/system dirs
    # - keep a log we can parse
    (
      clamscan \
        -r \
        --infected \
        --no-summary \
        --exclude-dir='^/proc/' \
        --exclude-dir='^/sys/' \
        --exclude-dir='^/dev/' \
        --exclude-dir='^/run/' \
        --exclude-dir='^/tmp/' \
        --exclude-dir='/.*/' \
        / \
        2>&1
      echo
      clamscan -r --infected --exclude-dir='^/proc/' --exclude-dir='^/sys/' --exclude-dir='^/dev/' --exclude-dir='^/run/' --exclude-dir='^/tmp/' --exclude-dir='/.*/' / --summary 2>/dev/null || true
    ) | sed -e 's/\r$//' > "${log_file}"

    : > "${det_tsv}"
    # Parse "PATH: SIGNATURE FOUND" lines.
    grep -E ' FOUND$' "${log_file}" | sed -E 's/: (.+) FOUND$//;t;d' >/dev/null 2>&1 || true
    while IFS= read -r line; do
      # Example: /path/file: Eicar-Test-Signature FOUND
      pth="${line%%:*}"
      rest="${line#*: }"
      sig="${rest% FOUND}"
      printf '%s\t%s\n' "${pth}" "${sig}" >> "${det_tsv}"
    done < <(grep -E ' FOUND$' "${log_file}" || true)

    infected_count="$(wc -l < "${det_tsv}" 2>/dev/null || echo 0)"
    severity="info"
    summary="ClamAV scan completed: no threats"
    if [[ "${infected_count}" -gt 0 ]]; then
      severity="bad"
      summary="ClamAV scan completed: ${infected_count} threat(s) found"
    fi

    rpt="$(write_scan_report "scan-${ts}" "${summary}" "${severity}" "${log_file}" "${det_tsv}" "${cmd}")"
    echo "${rpt}"
    ;;

  quarantine)
    target="${1:-}"
    if [[ -z "${target}" ]]; then
      echo "missing file path" >&2
      exit 2
    fi
    ts="$(date -u +%Y%m%dT%H%M%SZ)"
    bn="$(basename -- "${target}" 2>/dev/null || echo file)"
    dest="${QUAR_DIR}/${ts}-${bn}"
    if [[ ! -f "${target}" ]]; then
      rpt="$(write_report "quarantine-${ts}" "Quarantine failed: file not found" "warn" "${cmd}")"
      echo "${rpt}"
      exit 1
    fi
    mv -f -- "${target}" "${dest}" 2>>"${LOG_DIR}/saikyo-av-admin.log" || {
      rpt="$(write_report "quarantine-${ts}" "Quarantine failed: move error" "warn" "${cmd}")"
      echo "${rpt}"
      exit 1
    }
    rpt="$(write_report "quarantine-${ts}" "File quarantined" "warn" "${cmd}")"
    sed -i "s#\"artifacts\": {}#\"artifacts\": {\"from\": \"${target}\", \"to\": \"${dest}\"}#" "${rpt}" || true
    echo "${rpt}"
    ;;

  delete)
    target="${1:-}"
    if [[ -z "${target}" ]]; then
      echo "missing file path" >&2
      exit 2
    fi
    ts="$(date -u +%Y%m%dT%H%M%SZ)"
    if [[ ! -e "${target}" ]]; then
      rpt="$(write_report "delete-${ts}" "Delete failed: path not found" "warn" "${cmd}")"
      echo "${rpt}"
      exit 1
    fi
    rm -rf -- "${target}" 2>>"${LOG_DIR}/saikyo-av-admin.log" || {
      rpt="$(write_report "delete-${ts}" "Delete failed" "warn" "${cmd}")"
      echo "${rpt}"
      exit 1
    }
    rpt="$(write_report "delete-${ts}" "File deleted" "warn" "${cmd}")"
    sed -i "s#\"artifacts\": {}#\"artifacts\": {\"path\": \"${target}\"}#" "${rpt}" || true
    echo "${rpt}"
    ;;

  run-audit)
    outdir="${REPORTS_DIR}/artifacts"
    mkdir -p "${outdir}" || true
    ts="$(date -u +%Y%m%dT%H%M%SZ)"
    audit_out="${outdir}/saikyo-audit-report-${ts}.txt"

    if command -v saikyo-audit-report >/dev/null 2>&1; then
      run_to_file "${audit_out}" saikyo-audit-report
    else
      echo "saikyo-audit-report not installed" > "${audit_out}"
    fi

    rpt="$(write_report "audit-${ts}" "Audit report executed" "info" "${cmd}")"
    sed -i "s#\"artifacts\": {}#\"artifacts\": {\"audit_stdout\": \"${audit_out}\"}#" "${rpt}" || true
    echo "${rpt}"
    ;;

  collect-artifacts)
    outdir="${REPORTS_DIR}/artifacts"
    mkdir -p "${outdir}" || true
    ts="$(date -u +%Y%m%dT%H%M%SZ)"
    collect_out="${outdir}/collect-artifacts-${ts}.log"

    if [ -x /usr/share/saikyo-os/forensics/collect-artifacts.sh ]; then
      run_to_file "${collect_out}" /usr/share/saikyo-os/forensics/collect-artifacts.sh
    else
      echo "collect-artifacts.sh not found" > "${collect_out}"
    fi

    rpt="$(write_report "collect-${ts}" "Artifacts collection executed" "info" "${cmd}")"
    sed -i "s#\"artifacts\": {}#\"artifacts\": {\"collector_log\": \"${collect_out}\"}#" "${rpt}" || true
    echo "${rpt}"
    ;;

  enable-protection)
    ts="$(date -u +%Y%m%dT%H%M%SZ)"
    (systemctl daemon-reload 2>&1 || true) >> "${LOG_DIR}/saikyo-av-admin.log" || true
    if systemctl enable --now saikyo-avd.timer >/dev/null 2>&1; then
      rpt="$(write_report "enable-${ts}" "Protection enabled" "info" "${cmd}")"
      echo "${rpt}"
      exit 0
    else
      rpt="$(write_report "enable-${ts}" "Protection enable failed" "warn" "${cmd}")"
      echo "${rpt}"
      exit 1
    fi
    ;;

  disable-protection)
    ts="$(date -u +%Y%m%dT%H%M%SZ)"
    (systemctl daemon-reload 2>&1 || true) >> "${LOG_DIR}/saikyo-av-admin.log" || true
    if systemctl disable --now saikyo-avd.timer >/dev/null 2>&1; then
      rpt="$(write_report "disable-${ts}" "Protection disabled" "warn" "${cmd}")"
      echo "${rpt}"
      exit 0
    else
      rpt="$(write_report "disable-${ts}" "Protection disable failed" "warn" "${cmd}")"
      echo "${rpt}"
      exit 1
    fi
    ;;

  *)
    echo "Usage: saikyo-av-admin {health|status-protection|run-evidence|run-audit|collect-artifacts|scan|quarantine <file>|delete <file>|enable-protection|disable-protection}" >&2
    exit 2
    ;;
esac
