'use strict';

const crypto = require('crypto');

const DEFAULT_TTL_MS = 5 * 60 * 1000;

function _flowStore() {
  if (!global._walleAuthFlows) global._walleAuthFlows = Object.create(null);
  return global._walleAuthFlows;
}

function _timerStore() {
  if (!global._walleAuthFlowTimers) global._walleAuthFlowTimers = Object.create(null);
  return global._walleAuthFlowTimers;
}

function _cleanup(flowId) {
  const flows = _flowStore();
  const timers = _timerStore();
  if (timers[flowId]) {
    clearTimeout(timers[flowId]);
    delete timers[flowId];
  }
  delete flows[flowId];
}

function _scheduleCleanup(flowId, ttlMs) {
  const timers = _timerStore();
  if (timers[flowId]) clearTimeout(timers[flowId]);
  timers[flowId] = setTimeout(() => _cleanup(flowId), ttlMs || DEFAULT_TTL_MS);
  if (typeof timers[flowId].unref === 'function') timers[flowId].unref();
}

function _clone(flow) {
  return flow ? JSON.parse(JSON.stringify(flow)) : null;
}

function _response(flow) {
  if (!flow) return null;
  const metadata = flow.metadata || {};
  return {
    flowId: flow.flowId,
    status: flow.status,
    provider: flow.provider,
    principal: flow.principal || null,
    profileId: flow.profileId || null,
    email: metadata.email || (flow.provider === 'google' ? flow.principal || null : null),
    user: metadata.user || (flow.provider === 'slack' ? flow.principal || null : null),
    team: metadata.team || null,
    teamId: metadata.teamId || null,
    error: flow.error || null,
    metadata,
    createdAt: flow.createdAt,
    updatedAt: flow.updatedAt,
  };
}

function createAuthFlow(opts = {}) {
  const provider = String(opts.provider || '').trim();
  if (!provider) throw new Error('provider is required');
  const now = new Date().toISOString();
  const flowId = `${provider}-${Date.now().toString(36)}-${crypto.randomBytes(16).toString('hex')}`;
  const flow = {
    flowId,
    provider,
    principal: opts.principal || null,
    profileId: opts.profileId || null,
    status: 'pending',
    error: null,
    metadata: opts.metadata || {},
    createdAt: now,
    updatedAt: now,
  };
  _flowStore()[flowId] = flow;
  _scheduleCleanup(flowId, opts.ttlMs || DEFAULT_TTL_MS);
  return _clone(flow);
}

function updateAuthFlow(flowId, updates = {}) {
  const flows = _flowStore();
  const flow = flows[flowId];
  if (!flow) return null;
  const next = {
    ...flow,
    ...updates,
    metadata: { ...(flow.metadata || {}), ...(updates.metadata || {}) },
    updatedAt: new Date().toISOString(),
  };
  flows[flowId] = next;
  return _clone(next);
}

function completeAuthFlow(flowId, updates = {}) {
  return updateAuthFlow(flowId, {
    ...updates,
    status: 'complete',
    error: null,
  });
}

function failAuthFlow(flowId, error, updates = {}) {
  return updateAuthFlow(flowId, {
    ...updates,
    status: 'error',
    error: error && error.message ? error.message : String(error || 'Authentication failed'),
  });
}

function getAuthFlow(flowId) {
  return _clone(_flowStore()[flowId]);
}

function getAuthFlowResponse(flowId) {
  return _response(_flowStore()[flowId]);
}

function resetAuthFlowsForTests() {
  const flows = _flowStore();
  const timers = _timerStore();
  for (const id of Object.keys(timers)) clearTimeout(timers[id]);
  for (const id of Object.keys(timers)) delete timers[id];
  for (const id of Object.keys(flows)) delete flows[id];
}

module.exports = {
  createAuthFlow,
  updateAuthFlow,
  completeAuthFlow,
  failAuthFlow,
  getAuthFlow,
  getAuthFlowResponse,
  resetAuthFlowsForTests,
};
