import { logger } from '@goodgo/logger';
import { PrismaClient } from '@prisma/client';
import { Request } from 'express';

import { getPrismaClient } from '../../config/database.config';
import { cacheService } from '../../core/cache/cache.service';
import { SessionResponse } from '../../types/auth.types';
import { cookieService } from '../token/cookie.service';


/**
 * EN: Session Service for distributed session management
 * VI: Service Session cho quản lý phiên phân tán
 */
export class SessionService {
  private prisma: PrismaClient;

  constructor() {
    this.prisma = getPrismaClient();
  }

  /**
   * EN: Create new session
   * VI: Tạo phiên mới
   */
  async createSession(
    userId: string,
    req: Request,
    expiresInMinutes: number = 60 * 24 * 7 // 7 days default
  ): Promise<SessionResponse> {
    const deviceId = cookieService.getDeviceFingerprint(req);
    const deviceName = req.headers['user-agent'] || 'Unknown Device';
    const ipAddress = req.ip || req.socket.remoteAddress || 'unknown';
    const userAgent = req.headers['user-agent'] || '';

    const expiresAt = new Date();
    expiresAt.setMinutes(expiresAt.getMinutes() + expiresInMinutes);

    const session = await this.prisma.session.create({
      data: {
        userId,
        deviceId,
        deviceName,
        ipAddress,
        userAgent,
        fingerprint: deviceId,
        expiresAt,
        isActive: true,
      },
    });

    // Cache session
    await cacheService.set(
      cacheService.keys.session(session.id),
      session,
      expiresInMinutes * 60
    );

    logger.info('Session created', { userId, sessionId: session.id });
    return {
      id: session.id,
      userId: session.userId,
      deviceId: session.deviceId,
      deviceName: session.deviceName ?? undefined,
      ipAddress: session.ipAddress ?? undefined,
      userAgent: session.userAgent ?? undefined,
      expiresAt: session.expiresAt,
      isActive: session.isActive,
      lastActivityAt: session.lastActivityAt,
    };
  }

  /**
   * EN: Get session by ID
   * VI: Lấy phiên theo ID
   */
  async getSession(sessionId: string): Promise<SessionResponse | null> {
    // Try cache first
    const cached = await cacheService.get<SessionResponse>(cacheService.keys.session(sessionId));
    if (cached) {
      return cached;
    }

    const session = await this.prisma.session.findUnique({
      where: { id: sessionId },
      include: { user: true },
    });

    if (session && session.isActive && session.expiresAt > new Date()) {
      const sessionResponse: SessionResponse = {
        id: session.id,
        userId: session.userId,
        deviceId: session.deviceId,
        deviceName: session.deviceName ?? undefined,
        ipAddress: session.ipAddress ?? undefined,
        userAgent: session.userAgent ?? undefined,
        expiresAt: session.expiresAt,
        isActive: session.isActive,
        lastActivityAt: session.lastActivityAt,
      };
      // Cache for 1 hour
      await cacheService.set(cacheService.keys.session(sessionId), sessionResponse, 3600);
      return sessionResponse;
    }

    return null;
  }

  /**
   * EN: Update session activity
   * VI: Cập nhật hoạt động phiên
   */
  async updateActivity(sessionId: string): Promise<void> {
    await this.prisma.session.update({
      where: { id: sessionId },
      data: { lastActivityAt: new Date() },
    });

    // Invalidate cache to force refresh
    await cacheService.del(cacheService.keys.session(sessionId));
  }

  /**
   * EN: Revoke session
   * VI: Thu hồi phiên
   */
  async revokeSession(sessionId: string): Promise<void> {
    await this.prisma.session.update({
      where: { id: sessionId },
      data: { isActive: false },
    });

    await cacheService.del(cacheService.keys.session(sessionId));
    logger.info('Session revoked', { sessionId });
  }

  /**
   * EN: Revoke all user sessions
   * VI: Thu hồi tất cả phiên của người dùng
   */
  async revokeAllUserSessions(userId: string): Promise<void> {
    await this.prisma.session.updateMany({
      where: { userId, isActive: true },
      data: { isActive: false },
    });

    // Invalidate all cached sessions (pattern matching)
    await cacheService.invalidatePattern(`session:*`);
    logger.info('All user sessions revoked', { userId });
  }

  /**
   * EN: Clean expired sessions
   * VI: Dọn dẹp phiên hết hạn
   */
  async cleanExpiredSessions(): Promise<void> {
    const result = await this.prisma.session.deleteMany({
      where: {
        expiresAt: { lt: new Date() },
      },
    });

    logger.info('Expired sessions cleaned', { count: result.count });
  }

  /**
   * EN: Get user active sessions
   * VI: Lấy các phiên hoạt động của người dùng
   */
  async getUserSessions(userId: string): Promise<SessionResponse[]> {
    const sessions = await this.prisma.session.findMany({
      where: {
        userId,
        isActive: true,
        expiresAt: { gt: new Date() },
      },
      orderBy: { lastActivityAt: 'desc' },
    });

    return sessions.map(session => ({
      id: session.id,
      userId: session.userId,
      deviceId: session.deviceId,
      deviceName: session.deviceName ?? undefined,
      ipAddress: session.ipAddress ?? undefined,
      userAgent: session.userAgent ?? undefined,
      expiresAt: session.expiresAt,
      isActive: session.isActive,
      lastActivityAt: session.lastActivityAt,
    }));
  }
}

export const sessionService = new SessionService();
