import { Request, Response, NextFunction } from 'express';
import { AuthService } from '../services/auth.service';
import config from '../config';

// Temporary mock for prisma until database is properly set up
const prisma = {
  user: {
    findUnique: async (params: any): Promise<any> => {
      // Mock implementation for development
      return {
        id: 'mock-user-id',
        email: 'mock@example.com',
        subscription: 'FREE',
        isActive: true,
        passwordHash: '$2b$12$mockhashedpassword'
      };
    }
  },
  userSession: {
    create: async (params: any): Promise<any> => {
      // Mock implementation for development
      return { id: 'mock-session' };
    },
    deleteMany: async (params: any): Promise<any> => {
      // Mock implementation for development
      return { count: 0 };
    }
  }
};

// Extend Request interface to include user
declare global {
  namespace Express {
    interface Request {
      user?: {
        id: string;
        email: string;
        subscription: string;
        roles: string[];
      };
    }
  }
}

export interface JWTPayload {
  userId: string;
  email: string;
  subscription: string;
  type: 'access' | 'refresh';
  sessionId: string;
  iat?: number;
  exp?: number;
}

// Authentication middleware
export const authenticateToken = async (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  try {
    const authHeader = req.headers.authorization;
    const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
    
    if (!token) {
      return res.status(401).json({
        success: false,
        error: 'Access token required',
        code: 'AUTHENTICATION_ERROR'
      });
    }
    
    // Verify JWT token using AuthService
    const decoded = AuthService.verifyToken(token);
    
    // Ensure it's an access token
    if (decoded.type !== 'access') {
      return res.status(401).json({
        success: false,
        error: 'Invalid token type',
        code: 'AUTHENTICATION_ERROR'
      });
    }
    
    // Get user from database to ensure they still exist and are active
    const user = await prisma.user.findUnique({
      where: { id: decoded.userId },
      select: {
        id: true,
        email: true,
        subscription: true,
        isActive: true,
      }
    });
    
    if (!user || !user.isActive) {
      return res.status(401).json({
        success: false,
        error: 'Invalid or expired token',
        code: 'AUTHENTICATION_ERROR'
      });
    }
    
    // Add user to request object
    req.user = {
      id: user.id,
      email: user.email,
      subscription: user.subscription,
      roles: ['user'] // Basic role, can be extended
    };
    
    next();
  } catch (error) {
    if (error instanceof Error) {
      if (error.message.includes('blacklisted')) {
        return res.status(401).json({
          success: false,
          error: 'Token has been revoked',
          code: 'TOKEN_REVOKED'
        });
      }
      
      if (error.message.includes('expired')) {
        return res.status(401).json({
          success: false,
          error: 'Token expired',
          code: 'TOKEN_EXPIRED'
        });
      }
    }
    
    return res.status(401).json({
      success: false,
      error: 'Invalid token',
      code: 'AUTHENTICATION_ERROR'
    });
  }
};

// Optional authentication (doesn't fail if no token)
export const optionalAuth = async (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  try {
    const authHeader = req.headers.authorization;
    const token = authHeader && authHeader.split(' ')[1];
    
    if (token) {
      const decoded = AuthService.verifyToken(token);
      
      if (decoded.type === 'access') {
        const user = await prisma.user.findUnique({
          where: { id: decoded.userId },
          select: {
            id: true,
            email: true,
            subscription: true,
            isActive: true,
          }
        });
        
        if (user && user.isActive) {
          req.user = {
            id: user.id,
            email: user.email,
            subscription: user.subscription,
            roles: ['user']
          };
        }
      }
    }
    
    next();
  } catch (error) {
    // Ignore authentication errors for optional auth
    next();
  }
};

// Authorization middleware factory
export const requireRole = (roles: string[]) => {
  return (req: Request, res: Response, next: NextFunction) => {
    if (!req.user) {
      return res.status(401).json({
        success: false,
        error: 'Authentication required',
        code: 'AUTHENTICATION_ERROR'
      });
    }
    
    const hasRole = roles.some(role => req.user!.roles.includes(role));
    
    if (!hasRole) {
      return res.status(403).json({
        success: false,
        error: 'Insufficient permissions',
        code: 'AUTHORIZATION_ERROR'
      });
    }
    
    next();
  };
};

// Subscription tier middleware
export const requireSubscription = (minTier: string) => {
  const tierHierarchy = ['FREE', 'BASIC', 'PRO', 'ENTERPRISE'];
  
  return (req: Request, res: Response, next: NextFunction) => {
    if (!req.user) {
      return res.status(401).json({
        success: false,
        error: 'Authentication required',
        code: 'AUTHENTICATION_ERROR'
      });
    }
    
    const userTierIndex = tierHierarchy.indexOf(req.user.subscription);
    const requiredTierIndex = tierHierarchy.indexOf(minTier);
    
    if (userTierIndex < requiredTierIndex) {
      return res.status(403).json({
        success: false,
        error: `${minTier} subscription or higher required`,
        code: 'SUBSCRIPTION_REQUIRED'
      });
    }
    
    next();
  };
};

// Generate JWT token pair
export const generateTokenPair = (userId: string, email: string, subscription: string) => {
  return AuthService.generateTokenPair(userId, email, subscription);
};

// Verify JWT token
export const verifyToken = (token: string) => {
  return AuthService.verifyToken(token);
};

// Blacklist token
export const blacklistToken = (token: string) => {
  return AuthService.blacklistToken(token);
};