import { z } from 'zod';
import jwt from 'jsonwebtoken';
import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import pino from 'pino';

const logger = pino({ name: 'auth' });

export interface AuthPayload {
  tenantId: string;
  userId: string;
  email: string;
  role: 'owner' | 'admin' | 'member' | 'viewer';
}

/**
 * JWT auth middleware. Extracts tenant context from Bearer token.
 * Also supports API key auth via `X-API-Key` header (dd0c_ prefix).
 */
export function registerAuth(app: FastifyInstance, jwtSecret: string, pool: any) {
  app.decorateRequest('tenantId', '');
  app.decorateRequest('userId', '');
  app.decorateRequest('userRole', 'viewer');

  app.addHook('onRequest', async (req: FastifyRequest, reply: FastifyReply) => {
    // Skip health check
    if (req.url === '/health') return;
    // Skip webhook endpoints (they use HMAC auth)
    if (req.url.startsWith('/webhooks/')) return;
    // Skip Slack endpoints (they use Slack signature)
    if (req.url.startsWith('/slack/')) return;

    const apiKey = req.headers['x-api-key'] as string | undefined;
    const authHeader = req.headers['authorization'];

    if (apiKey) {
      // API key auth: dd0c_ prefix + 32 hex chars
      if (!apiKey.startsWith('dd0c_') || apiKey.length !== 37) {
        return reply.status(401).send({ error: 'Invalid API key format' });
      }

      const prefix = apiKey.slice(0, 13); // dd0c_ + 8 hex chars for fast lookup
      // TODO: Look up by prefix, bcrypt compare full key
      // For now, reject — real implementation needs DB lookup
      return reply.status(401).send({ error: 'API key auth not yet implemented' });
    }

    if (authHeader?.startsWith('Bearer ')) {
      const token = authHeader.slice(7);
      try {
        const payload = jwt.verify(token, jwtSecret) as AuthPayload;
        (req as any).tenantId = payload.tenantId;
        (req as any).userId = payload.userId;
        (req as any).userRole = payload.role;
        return;
      } catch (err) {
        return reply.status(401).send({ error: 'Invalid or expired token' });
      }
    }

    return reply.status(401).send({ error: 'Missing authentication' });
  });
}

/**
 * Role-based access control check.
 * Use in route handlers: requireRole(req, reply, 'admin')
 */
export function requireRole(req: FastifyRequest, reply: FastifyReply, minRole: AuthPayload['role']): boolean {
  const hierarchy: Record<string, number> = { owner: 4, admin: 3, member: 2, viewer: 1 };
  const userLevel = hierarchy[(req as any).userRole] ?? 0;
  const requiredLevel = hierarchy[minRole] ?? 0;

  if (userLevel < requiredLevel) {
    reply.status(403).send({ error: `Requires ${minRole} role or higher` });
    return false;
  }
  return true;
}

/**
 * Generate a JWT token (for login/signup endpoints).
 */
export function signToken(payload: AuthPayload, secret: string, expiresIn = '24h'): string {
  return jwt.sign(payload, secret, { expiresIn });
}

/**
 * Login endpoint registration.
 */
const loginSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
});

const signupSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
  tenant_name: z.string().min(1).max(100),
});

export function registerAuthRoutes(app: FastifyInstance, jwtSecret: string, pool: any) {
  app.post('/api/v1/auth/login', async (req, reply) => {
    const body = loginSchema.parse(req.body);
    // TODO: Look up user by email, bcrypt compare password
    // For now, return placeholder
    return reply.status(501).send({ error: 'Login not yet implemented' });
  });

  app.post('/api/v1/auth/signup', async (req, reply) => {
    const body = signupSchema.parse(req.body);
    // TODO: Create tenant + user, hash password with bcrypt
    return reply.status(501).send({ error: 'Signup not yet implemented' });
  });

  app.get('/api/v1/auth/me', async (req, reply) => {
    return {
      tenant_id: (req as any).tenantId,
      user_id: (req as any).userId,
      role: (req as any).userRole,
    };
  });
}
