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

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SERVER_DIR="$ROOT_DIR/server"
APP_DIR="$ROOT_DIR/app"
MARKER_FILE="${APP_SETUP_MARKER:-$ROOT_DIR/.app-setup-complete}"
FORCE_SETUP="${FORCE_SETUP:-0}"

log() {
  printf '[setup] %s\n' "$*"
}

install_dependencies() {
  local dir="$1"
  log "Installing dependencies in ${dir#$ROOT_DIR/}..."
  if [[ -f "$dir/package-lock.json" ]]; then
    npm ci --prefix "$dir"
  else
    npm install --prefix "$dir"
  fi
}

ensure_server_env() {
  if [[ ! -f "$SERVER_DIR/.env" && -f "$SERVER_DIR/.env.example" ]]; then
    log "Creating server/.env from server/.env.example. Review production secrets before starting the app."
    cp "$SERVER_DIR/.env.example" "$SERVER_DIR/.env"
  fi
}

run_node_setup_check() {
  (cd "$SERVER_DIR" && node <<'NODE'
const path = require('node:path');
require('dotenv').config({ path: path.join(process.cwd(), '.env') });

const { Client } = require('pg');

async function main() {
  const connectionString = process.env.DATABASE_URL;
  if (!connectionString) {
    console.error('DATABASE_URL is required in the environment or server/.env.');
    process.exit(2);
  }

  const client = new Client({ connectionString });
  await client.connect();

  try {
    const tables = await client.query(`
      SELECT
        to_regclass('public.platform_settings') AS platform_settings,
        to_regclass('public.users') AS users
    `);

    if (tables.rows[0].platform_settings) {
      const flag = await client.query(
        "SELECT value FROM platform_settings WHERE key = 'app_setup_complete' LIMIT 1"
      );
      const value = flag.rows[0]?.value;
      if (value === true || value === 'true' || value?.setupComplete === true) {
        process.exit(10);
      }
    }

    if (tables.rows[0].users) {
      const users = await client.query('SELECT COUNT(*)::int AS count FROM users');
      if (Number(users.rows[0]?.count ?? 0) > 0) {
        process.exit(10);
      }
    }
  } finally {
    await client.end();
  }
}

main().catch((error) => {
  console.error(error.message || error);
  process.exit(1);
});
NODE
  )
}

write_setup_flag() {
  (cd "$SERVER_DIR" && node <<'NODE'
const path = require('node:path');
require('dotenv').config({ path: path.join(process.cwd(), '.env') });

const { Client } = require('pg');

async function main() {
  const client = new Client({ connectionString: process.env.DATABASE_URL });
  await client.connect();
  try {
    await client.query(
      `INSERT INTO platform_settings (key, value, description)
       VALUES ($1, $2::jsonb, $3)
       ON CONFLICT (key)
       DO UPDATE SET value = EXCLUDED.value, description = EXCLUDED.description, updated_at = now()`,
      ['app_setup_complete', JSON.stringify(true), 'Application setup has completed successfully.']
    );
  } finally {
    await client.end();
  }
}

main().catch((error) => {
  console.error(error.message || error);
  process.exit(1);
});
NODE
  )
}

if [[ "$FORCE_SETUP" != "1" && -f "$MARKER_FILE" ]]; then
  log "Setup marker exists at $MARKER_FILE. Nothing to do."
  exit 0
fi

ensure_server_env
install_dependencies "$SERVER_DIR"
install_dependencies "$APP_DIR"

if [[ "$FORCE_SETUP" != "1" ]]; then
  set +e
  run_node_setup_check
  check_status=$?
  set -e

  if [[ "$check_status" -eq 10 ]]; then
    log "Application already appears to be setup in the database. Writing local marker and exiting."
    printf 'setup_completed_at=%s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" > "$MARKER_FILE"
    exit 0
  fi

  if [[ "$check_status" -ne 0 ]]; then
    log "Setup check failed."
    exit "$check_status"
  fi
fi

log "Building backend..."
npm run build --prefix "$SERVER_DIR"

log "Building frontend..."
npm run build --prefix "$APP_DIR"

log "Applying database migrations..."
npm run db:migrate:deploy --prefix "$SERVER_DIR"

log "Seeding database..."
npm run db:seed --prefix "$SERVER_DIR"

log "Writing setup-complete marker..."
write_setup_flag
printf 'setup_completed_at=%s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" > "$MARKER_FILE"

log "Setup complete."
