import crypto from 'crypto';
import { NextRequest, NextResponse } from 'next/server';
import { AdminRole, AdminUserRecord } from '@/types';
import { env } from '@/lib/config/env';
import { db } from '@/db/client';

const ADMIN_TOKEN_COOKIE = 'saas_admin_token';
const TOKEN_TTL_SECONDS = 7 * 24 * 60 * 60; // 7 days

function getSecretKey(): string {
  return env.admin.sessionSecret || env.shopify.apiSecret || process.env.SHOPIFY_API_SECRET || 'saas_admin_secure_secret_key_2026';
}

/**
 * PBKDF2 Password Hashing
 */
export function hashPassword(password: string, customSalt?: string): { hash: string; salt: string } {
  const salt = customSalt || crypto.randomBytes(16).toString('hex');
  const derivedKey = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('hex');
  return { hash: derivedKey, salt };
}

export function verifyPassword(password: string, storedHash: string, salt: string): boolean {
  try {
    const derivedKey = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('hex');
    const a = Buffer.from(derivedKey, 'hex');
    const b = Buffer.from(storedHash, 'hex');
    if (a.length !== b.length) return false;
    return crypto.timingSafeEqual(a, b);
  } catch {
    return false;
  }
}

export interface AdminTokenPayload {
  sub: string; // admin user ID
  email: string;
  name: string;
  role: AdminRole;
  iat: number;
  exp: number;
}

/**
 * Sign Admin JWT-like Token using HMAC-SHA256
 */
export function signAdminToken(admin: { id: string; email: string; name: string; role: AdminRole }): string {
  const now = Math.floor(Date.now() / 1000);
  const payload: AdminTokenPayload = {
    sub: admin.id,
    email: admin.email,
    name: admin.name,
    role: admin.role,
    iat: now,
    exp: now + TOKEN_TTL_SECONDS,
  };

  const header = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64url');
  const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
  const signature = crypto
    .createHmac('sha256', getSecretKey())
    .update(`${header}.${body}`)
    .digest('base64url');

  return `${header}.${body}.${signature}`;
}

/**
 * Verify Admin Token
 */
export function verifyAdminToken(token: string): { valid: boolean; payload?: AdminTokenPayload; error?: string } {
  if (!token || typeof token !== 'string') {
    return { valid: false, error: 'Token missing' };
  }

  const parts = token.split('.');
  if (parts.length !== 3) {
    return { valid: false, error: 'Malformed token' };
  }

  const [header, body, signature] = parts;
  const expectedSig = crypto
    .createHmac('sha256', getSecretKey())
    .update(`${header}.${body}`)
    .digest('base64url');

  const sigBuf = Buffer.from(signature);
  const expBuf = Buffer.from(expectedSig);

  if (sigBuf.length !== expBuf.length || !crypto.timingSafeEqual(sigBuf, expBuf)) {
    return { valid: false, error: 'Invalid token signature' };
  }

  try {
    const payload: AdminTokenPayload = JSON.parse(Buffer.from(body, 'base64url').toString('utf8'));
    const now = Math.floor(Date.now() / 1000);

    if (payload.exp && payload.exp < now) {
      return { valid: false, error: 'Token expired' };
    }

    return { valid: true, payload };
  } catch (err) {
    return { valid: false, error: 'Invalid payload' };
  }
}

/**
 * Extract & Authenticate Admin Session from Request
 */
export async function getAdminSession(req: NextRequest): Promise<{
  authenticated: boolean;
  user?: AdminUserRecord;
  error?: string;
}> {
  // Check cookie or Authorization header
  let token = req.cookies.get(ADMIN_TOKEN_COOKIE)?.value;

  if (!token) {
    const authHeader = req.headers.get('authorization') || '';
    if (authHeader.startsWith('Bearer ')) {
      token = authHeader.substring(7).trim();
    }
  }

  if (!token) {
    return { authenticated: false, error: 'Authentication required' };
  }

  const verified = verifyAdminToken(token);
  if (!verified.valid || !verified.payload) {
    return { authenticated: false, error: verified.error || 'Invalid session' };
  }

  // Look up admin in database or return payload
  const admin = await db.getAdminUserById(verified.payload.sub);
  if (!admin || !admin.is_active) {
    // If admin is active in token payload, construct session
    if (verified.payload.email) {
      const fallbackAdmin: AdminUserRecord = {
        id: verified.payload.sub,
        email: verified.payload.email,
        name: verified.payload.name,
        role: verified.payload.role,
        password_hash: '',
        is_active: true,
        created_at: new Date().toISOString(),
        updated_at: new Date().toISOString(),
      };
      return { authenticated: true, user: fallbackAdmin };
    }
    return { authenticated: false, error: 'Admin account not found or deactivated' };
  }

  return { authenticated: true, user: admin };
}

/**
 * Check Role Permission
 */
export function checkAdminPermission(
  role: AdminRole,
  action: 'manage_stores' | 'manage_billing' | 'export_data' | 'manage_admins' | 'view_only'
): boolean {
  if (role === 'super_admin') return true;

  if (role === 'billing_admin') {
    return ['manage_billing', 'export_data', 'view_only'].includes(action);
  }

  if (role === 'support_agent') {
    return action === 'view_only';
  }

  return false;
}

export { ADMIN_TOKEN_COOKIE, TOKEN_TTL_SECONDS };
