const { audit, json, now, one, run } = require('../db');
const { upsertEmployee } = require('./assignments');

function publicConnection(row) {
  if (!row) return null;
  return {
    id: row.id,
    name: row.name,
    tenant: row.tenant,
    base_url: row.base_url,
    token_url: row.token_url,
    client_id: row.client_id,
    workers_path: row.workers_path,
    enabled: Boolean(row.enabled),
    last_sync_at: row.last_sync_at,
    last_sync_status: row.last_sync_status,
    configured: Boolean(row.base_url && row.token_url && row.client_id && row.client_secret)
  };
}

function getConnection() {
  return publicConnection(one('SELECT * FROM workday_connections ORDER BY id LIMIT 1'));
}

function getPrivateConnection() {
  return one('SELECT * FROM workday_connections ORDER BY id LIMIT 1');
}

function saveConnection(body, userId) {
  const timestamp = now();
  const existing = getPrivateConnection();
  const payload = {
    name: body.name || existing?.name || 'Primary Workday',
    tenant: body.tenant ?? existing?.tenant ?? '',
    base_url: body.base_url ?? existing?.base_url ?? '',
    token_url: body.token_url ?? existing?.token_url ?? '',
    client_id: body.client_id ?? existing?.client_id ?? '',
    client_secret: body.client_secret ? body.client_secret : existing?.client_secret ?? '',
    workers_path: body.workers_path ?? existing?.workers_path ?? '/workers',
    enabled: body.enabled === undefined ? Number(existing?.enabled || 0) : (body.enabled ? 1 : 0)
  };

  if (existing) {
    run(
      `UPDATE workday_connections SET
        name = ?, tenant = ?, base_url = ?, token_url = ?, client_id = ?, client_secret = ?,
        workers_path = ?, enabled = ?, updated_at = ?
      WHERE id = ?`,
      [payload.name, payload.tenant, payload.base_url, payload.token_url, payload.client_id, payload.client_secret, payload.workers_path, payload.enabled, timestamp, existing.id]
    );
  } else {
    run(
      `INSERT INTO workday_connections (
        name, tenant, base_url, token_url, client_id, client_secret, workers_path, enabled, created_at, updated_at
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
      [payload.name, payload.tenant, payload.base_url, payload.token_url, payload.client_id, payload.client_secret, payload.workers_path, payload.enabled, timestamp, timestamp]
    );
  }

  const saved = getConnection();
  audit(userId, 'update', 'workday_connection', saved.id, null, { ...saved, client_secret: '[redacted]' });
  return saved;
}

async function fetchAccessToken(connection) {
  const basic = Buffer.from(`${connection.client_id}:${connection.client_secret}`).toString('base64');
  const response = await fetch(connection.token_url, {
    method: 'POST',
    headers: {
      Authorization: `Basic ${basic}`,
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({ grant_type: 'client_credentials' })
  });
  if (!response.ok) {
    throw new Error(`Workday token request failed: ${response.status}`);
  }
  const body = await response.json();
  if (!body.access_token) throw new Error('Workday token response did not include an access token');
  return body.access_token;
}

function normalizeWorkers(payload) {
  const rows = Array.isArray(payload)
    ? payload
    : payload.workers || payload.Workers || payload.data || payload.value || [];

  return rows.map((worker) => ({
    workday_worker_id: worker.id || worker.workerId || worker.worker_id || worker.Worker_ID || worker.workerReference?.id,
    employee_number: worker.employeeNumber || worker.employee_number || worker.Worker_ID || worker.workerNumber,
    name: worker.name || worker.fullName || worker.Full_Name || worker.descriptor || [worker.firstName, worker.lastName].filter(Boolean).join(' '),
    email: worker.email || worker.workEmail || worker.primaryWorkEmail || worker.Email,
    department: worker.department || worker.organization || worker.Department || worker.supervisoryOrganization?.descriptor,
    location: worker.location || worker.workLocation || worker.Location || worker.location?.descriptor,
    manager_name: worker.managerName || worker.manager?.descriptor,
    status: worker.status || (worker.active === false ? 'inactive' : 'active'),
    source: 'workday',
    source_payload: worker,
    last_synced_at: now()
  }));
}

async function syncWorkers(userId) {
  const connection = getPrivateConnection();
  if (!connection || !connection.enabled) throw Object.assign(new Error('Workday connection is not enabled'), { status: 400 });
  if (!connection.base_url || !connection.token_url || !connection.client_id || !connection.client_secret) {
    throw Object.assign(new Error('Workday connection is missing URL or OAuth credentials'), { status: 400 });
  }

  const token = await fetchAccessToken(connection);
  const url = new URL(connection.workers_path || '/workers', connection.base_url);
  const response = await fetch(url, {
    headers: {
      Authorization: `Bearer ${token}`,
      Accept: 'application/json'
    }
  });
  if (!response.ok) {
    throw new Error(`Workday workers request failed: ${response.status}`);
  }

  const workers = normalizeWorkers(await response.json());
  for (const worker of workers) upsertEmployee(worker);

  const timestamp = now();
  run('UPDATE workday_connections SET last_sync_at = ?, last_sync_status = ?, updated_at = ? WHERE id = ?', [
    timestamp,
    `Imported ${workers.length} workers`,
    timestamp,
    connection.id
  ]);
  audit(userId, 'sync', 'workday_workers', connection.id, null, { imported: workers.length });
  return { imported: workers.length, workers };
}

function importWorkersFromPayload(workers, userId) {
  const normalized = normalizeWorkers(workers);
  for (const worker of normalized) upsertEmployee(worker);
  audit(userId, 'import', 'workday_workers', null, null, { imported: normalized.length, source: 'payload' });
  return { imported: normalized.length };
}

module.exports = {
  getConnection,
  importWorkersFromPayload,
  saveConnection,
  syncWorkers
};
