/**
 * Resolves the backoffice_session cookie into the current backoffice user.
 * Server-side truth: validity (expiry + revocation) and role come from the DB.
 */
import type { FastifyRequest } from 'fastify';
import type pg from 'pg';
import type { Authenticate } from '../../../shared/auth.js';
import { AppError } from '../../../shared/errors.js';
import { hashBackofficeToken } from './backoffice-session-token.js';
import { BACKOFFICE_SESSION_COOKIE_NAME } from '../api/backoffice.routes.js';

interface ResolvedRow {
  id: string;
  email: string;
  role: string;
}

const RESOLVE_SQL = `
  SELECT u.id, u.email, u.role
  FROM backoffice_sessions s
  JOIN backoffice_users u ON u.id = s.user_id
  WHERE s.token_hash = $1
    AND s.revoked_at IS NULL
    AND s.expires_at > now()
`;

export function createBackofficeSessionAuthenticator(pool: pg.Pool): Authenticate {
  return async (request: FastifyRequest) => {
    const token = request.cookies[BACKOFFICE_SESSION_COOKIE_NAME];
    if (!token) throw new AppError(401, 'UNAUTHORIZED', 'Backoffice authentication required');
    const result = await pool.query<ResolvedRow>(RESOLVE_SQL, [hashBackofficeToken(token)]);
    const row = result.rows[0];
    if (!row) throw new AppError(401, 'UNAUTHORIZED', 'Backoffice authentication required');
    return { id: row.id, email: row.email, role: row.role as 'admin' | 'editor' };
  };
}

/**
 * Combined authenticator for routes used by both backoffice and storefront
 * (e.g. /users — admin lists customers via backoffice, customer manages own
 * profile via storefront). Tries backoffice_session first, then mdv_session.
 */
export function createCombinedAuthenticator(pool: pg.Pool): Authenticate {
  const backofficeAuth = createBackofficeSessionAuthenticator(pool);
  const storefrontResolver = `
    SELECT u.id, u.email, u.role
    FROM identity_sessions s
    JOIN identity_users u ON u.id = s.user_id
    WHERE s.token_hash = $1 AND s.revoked_at IS NULL AND s.expires_at > now()
  `;
  return async (request: FastifyRequest) => {
    const backofficeToken = request.cookies[BACKOFFICE_SESSION_COOKIE_NAME];
    if (backofficeToken) {
      try {
        return await backofficeAuth(request);
      } catch {
        /* fallthrough */
      }
    }
    const storefrontToken = request.cookies['mdv_session'];
    if (storefrontToken) {
      const { createHash } = await import('node:crypto');
      const tokenHash = createHash('sha256').update(storefrontToken).digest('hex');
      const result = await pool.query<ResolvedRow>(storefrontResolver, [tokenHash]);
      const row = result.rows[0];
      if (row)
        return { id: row.id, email: row.email, role: row.role as 'customer' | 'admin' | 'editor' };
    }
    throw new AppError(401, 'UNAUTHORIZED', 'Authentication required');
  };
}
