import { ConductorResponse, SessionContext } from '../conductor/types.js';
import query from './query.js';

const handleHistoryDebug = async (id: string) => {
  const userQueryResult = await query(`SELECT * FROM users WHERE id = $1`, [id]);
  const user = userQueryResult.rows[0];
  const queryResult = await query(`SELECT * FROM conductor_requests WHERE user_id = $1 ORDER BY created_at ASC`, [id]);
  const output = queryResult.rows.reduce((acc, obj, i) => {
    const respObj = obj.response;
    acc += `\n------MSG ${i + 1}-----\n\n[REQUEST]\n${obj.request}\n\n[RESPONSE]\n${respObj.message}\n`;
    return acc;
  }, '');
  return `[HISTORY DEBUG]\n${queryResult.rows.length} messages found for user id ${id} (${user.display_name}, ${user.email})\n${output}`;
};

const handleUserDebug = async (id: string) => {
  const userQueryResult = await query(`SELECT * FROM users WHERE id = $1`, [id]);
  const identityQueryResult = await query(`SELECT * FROM user_identities WHERE user_id = $1`, [id]);
  const subQueryResult = await query(`SELECT * FROM subscription_updates WHERE user_id = $1`, [id]);

  const user = userQueryResult.rows[0];
  const identity = identityQueryResult.rows[0];
  const subscription = subQueryResult.rows[0];

  const subscriptionText = subscription
    ? `Subscribed from: ${new Date(subscription.created_at).toDateString()}\nSubscribed to: ${new Date(
        subscription.subscribed_until
      ).toDateString()}`
    : 'Subscription: none';

  return `[USER DEBUG]\nID: ${id}\nDisplay name: ${user.display_name}\nEmail: ${user.email}\nIssuer: ${identity.issuer}\nRole: ${user.role}\n${subscriptionText}`;
};

const handleActivityDebug = async (id: string, numHours?: number) => {
  const userQueryResult = await query(`SELECT * FROM users WHERE id = $1`, [id]);
  const activityQueryResult = await query(
    `SELECT * FROM activity WHERE user_id = $1${
      numHours ? ` AND created_at > NOW() - INTERVAL '1 HOUR' * $2` : ''
    } ORDER BY created_at ASC`,
    numHours ? [id, numHours] : [id]
  );

  const user = userQueryResult.rows[0];
  const activities = activityQueryResult.rows;

  const output = activities.reduce((acc, activity) => {
    return acc + `\n${new Date(activity.created_at).toLocaleString()}: ${activity.action}`;
  }, '');

  return `[ACTIVITY DEBUG]\n${activities.length} activities found for user id ${id} (${user.display_name}, ${
    user.email
  })${numHours ? ` in the last ${numHours} hours` : ''}:\n${output}`;
};

const handleLandingDebug = async (numHours: number = 24) => {
  const landingQueryResult = await query(
    `SELECT * FROM activity WHERE action = 'opened landing' AND created_at > NOW() - INTERVAL '1 HOUR' * $1`,
    [numHours]
  );
  const appOpenQueryResult = await query(
    `SELECT * FROM activity WHERE action = 'opened app' AND created_at > NOW() - INTERVAL '1 HOUR' * $1`,
    [numHours]
  );
  const signupQueryResult = await query(
    `SELECT * FROM activity WHERE action = 'signup' AND created_at > NOW() - INTERVAL '1 HOUR' * $1`,
    [numHours]
  );
  const loginQueryResult = await query(
    `SELECT * FROM activity WHERE action = 'login' AND created_at > NOW() - INTERVAL '1 HOUR' * $1`,
    [numHours]
  );

  return `[STATS DEBUG]\nIn the last ${numHours} hours:\n\n${landingQueryResult.rows.length} visits to the landing page.\n${appOpenQueryResult.rows.length} app opens.\n${signupQueryResult.rows.length} signups.\n${loginQueryResult.rows.length} logins.`;
};

const handleSessionDebug = async (sessionContext: SessionContext, args: string[]) => {
  if (args[0] === 'print') {
    return { sessionContext, returnMsg: JSON.stringify(sessionContext) };
  }
  if (args[0] === 'set') {
    sessionContext = JSON.parse(args.slice(1).join(' '));
  }
  // if (args[0] === 'setparam') {
  //   sessionContext.params[args[1]] = JSON.parse(args.slice(2).join(' '));
  // }
  return { sessionContext, returnMsg: 'sessionContext set to ' + JSON.stringify(sessionContext) };
};

const handleAddToBeta = async (email: string) => {
  const queryResult = await query(`SELECT * FROM users WHERE email = $1`, [email]);
  const user = queryResult.rows[0];
  if (!user) {
    return `ERROR: user with email ${email} not found`;
  }
  if (user.environment === 'beta') {
    return `ERROR: user with email ${email} is already in beta`;
  }
  if (user.environment === 'staging') {
    return `ERROR: user with email ${email} is already in staging`;
  }
  await query(`UPDATE users SET environment = 'beta' WHERE email = $1`, [email]);
  return `SUCCESS: user with email ${email} added to beta`;
};

export const handleDebugMessage = async (message): Promise<ConductorResponse> => {
  const [debugCommand, arg1, arg2, ...rest] = message.lines[message.lines.length - 1].message.split(' ');
  const args = [arg1, arg2, ...rest];
  const [_, debugType] = debugCommand.split(':');

  let returnMsg = `${debugType}: user ${arg1}`;
  let error = false;
  let { sessionContext } = message;

  try {
    if (debugType === 'addToBeta') returnMsg = await handleAddToBeta(arg1);
    if (debugType === 'history') returnMsg = await handleHistoryDebug(arg1);
    if (debugType === 'user') returnMsg = await handleUserDebug(arg1);
    if (debugType === 'activities' || debugType === 'activity') returnMsg = await handleActivityDebug(arg1, arg2);
    if (debugType === 'stats') returnMsg = await handleLandingDebug(arg1);
    if (debugType === 'session') {
      const res = await handleSessionDebug(sessionContext, args);
      sessionContext = res.sessionContext;
      returnMsg = res.returnMsg;
    }
  } catch (e) {
    returnMsg = `ERROR: ${e}`;
    error = true;
  }

  return { message: returnMsg, error, sessionContext };
};
