import crypto from 'crypto';
import { promises as fs } from 'fs';
import net from 'net';
import os from 'os';
import path from 'path';

export const CRON_DAEMON_OWNER_KIND = 'pilotdeck-server';
export const CRON_DAEMON_OWNER_KIND_ENV = 'PILOTDECK_CRON_DAEMON_OWNER_KIND';
export const CRON_DAEMON_OWNER_TOKEN_ENV = 'PILOTDECK_CRON_DAEMON_OWNER_TOKEN';
export const CRON_DAEMON_OWNER_PROCESS_PID_ENV = 'PILOTDECK_CRON_DAEMON_OWNER_PROCESS_PID';

function getPilotDeckConfigHomeDir() {
  return process.env.PILOTDECK_CONFIG_DIR || process.env.PILOT_HOME || path.join(os.homedir(), '.pilotdeck');
}

function getCronDaemonOwnerPath() {
  return path.join(getPilotDeckConfigHomeDir(), 'cron-daemon', 'owner.json');
}

function getCronDaemonSocketPath() {
  return path.join(getPilotDeckConfigHomeDir(), 'cron-daemon.sock');
}

async function readCronDaemonOwner() {
  try {
    const raw = await fs.readFile(getCronDaemonOwnerPath(), 'utf-8');
    const parsed = JSON.parse(raw);
    if (
      !parsed ||
      typeof parsed.kind !== 'string' ||
      typeof parsed.token !== 'string' ||
      typeof parsed.createdAt !== 'number'
    ) {
      return null;
    }

    return parsed;
  } catch {
    return null;
  }
}

function isCurrentProcessCronDaemonOwner(owner) {
  return Boolean(
    owner &&
    owner.kind === process.env[CRON_DAEMON_OWNER_KIND_ENV] &&
    owner.token === process.env[CRON_DAEMON_OWNER_TOKEN_ENV]
  );
}

function sendCronDaemonRequest(request) {
  return new Promise((resolve, reject) => {
    const socket = net.createConnection(getCronDaemonSocketPath());
    let settled = false;
    let buffer = '';

    const finalize = (callback, value) => {
      if (settled) return;
      settled = true;
      socket.destroy();
      callback(value);
    };

    socket.setTimeout(1000, () => {
      finalize(reject, new Error('Timed out waiting for Cron daemon response'));
    });

    socket.on('connect', () => {
      socket.write(`${JSON.stringify(request)}\n`);
    });

    socket.on('data', (chunk) => {
      buffer += chunk.toString('utf-8');
      const newlineIndex = buffer.indexOf('\n');
      if (newlineIndex === -1) {
        return;
      }
      const line = buffer.slice(0, newlineIndex);
      try {
        finalize(resolve, JSON.parse(line));
      } catch (error) {
        finalize(reject, error);
      }
    });

    socket.on('error', (error) => {
      finalize(reject, error);
    });
  });
}

export async function shutdownOwnedCronDaemon() {
  const owner = await readCronDaemonOwner();
  if (!isCurrentProcessCronDaemonOwner(owner)) {
    return false;
  }

  try {
    const response = await sendCronDaemonRequest({ type: 'shutdown' });
    return Boolean(response?.ok);
  } catch {
    return false;
  }
}

export async function _readCronDaemonOwnerForTest() {
  return await readCronDaemonOwner();
}

export {
  sendCronDaemonRequest
};
