import {
  Injectable,
  CanActivate,
  ExecutionContext,
  UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { PrismaService } from '../../infrastructure/database/prisma.service';
import { Request } from 'express';
import { ADMIN_PUBLIC_KEY } from '../decorators/admin-public.decorator';
import * as crypto from 'crypto';

function sha256(input: string): string {
  return crypto.createHash('sha256').update(input).digest('hex');
}

@Injectable()
export class AdminAuthGuard implements CanActivate {
  constructor(
    private readonly reflector: Reflector,
    private readonly jwtService: JwtService,
    private readonly configService: ConfigService,
    private readonly prisma: PrismaService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const isPublic = this.reflector.getAllAndOverride<boolean>(ADMIN_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic) return true;

    const request = context.switchToHttp().getRequest<Request>();

    // Try JWT Bearer token first, then x-api-key
    const token = this.extractToken(request);
    if (token) {
      return this.authenticateByJwt(request, token);
    }

    const apiKey = this.extractApiKey(request);
    if (apiKey) {
      return this.authenticateByApiKey(request, apiKey);
    }

    throw new UnauthorizedException('请先登录');
  }

  private async authenticateByJwt(request: Request, token: string): Promise<boolean> {
    try {
      const payload = await this.jwtService.verifyAsync(token, {
        secret: this.configService.get<string>('jwt.adminSecret'),
      });

      if (payload.type !== 'admin') {
        throw new UnauthorizedException('无效的管理员令牌');
      }

      const adminUser = await this.prisma.adminUser.findUnique({
        where: { id: payload.sub },
      });

      if (!adminUser || adminUser.deletedAt) {
        throw new UnauthorizedException('管理员账号不存在');
      }

      if (adminUser.status !== 'ACTIVE') {
        throw new UnauthorizedException('管理员账号已被禁用');
      }

      if (adminUser.lockedUntil && new Date(adminUser.lockedUntil) > new Date()) {
        throw new UnauthorizedException('管理员账号已被锁定，请稍后再试');
      }

      if (payload.sessionId) {
        const session = await this.prisma.adminSession.findUnique({
          where: { id: payload.sessionId },
        });

        if (!session || session.revokedAt) {
          throw new UnauthorizedException('会话已失效');
        }

        if (new Date(session.expiresAt) < new Date()) {
          throw new UnauthorizedException('会话已过期，请重新登录');
        }
      }

      (request as any).adminUser = adminUser;
      return true;
    } catch (err) {
      if (err instanceof UnauthorizedException) throw err;
      throw new UnauthorizedException('登录已过期，请重新登录');
    }
  }

  private async authenticateByApiKey(request: Request, rawKey: string): Promise<boolean> {
    const keyHash = sha256(rawKey);
    const apiKey = await this.prisma.adminApiKey.findUnique({ where: { keyHash } });

    if (!apiKey) {
      throw new UnauthorizedException('无效的 API Key');
    }

    if (apiKey.expiresAt && new Date(apiKey.expiresAt) < new Date()) {
      throw new UnauthorizedException('API Key 已过期');
    }

    const adminUser = await this.prisma.adminUser.findUnique({
      where: { id: apiKey.adminUserId },
    });

    if (!adminUser || adminUser.deletedAt) {
      throw new UnauthorizedException('管理员账号不存在');
    }

    if (adminUser.status !== 'ACTIVE') {
      throw new UnauthorizedException('管理员账号已被禁用');
    }

    if (adminUser.lockedUntil && new Date(adminUser.lockedUntil) > new Date()) {
      throw new UnauthorizedException('管理员账号已被锁定');
    }

    // Update lastUsedAt async (don't block the request)
    this.prisma.adminApiKey.update({
      where: { id: apiKey.id },
      data: { lastUsedAt: new Date() },
    }).catch(() => {});

    (request as any).adminUser = adminUser;
    (request as any).apiKeyId = apiKey.id;
    return true;
  }

  private extractToken(request: Request): string | undefined {
    // 优先从 httpOnly cookie 读取（新前端）
    const cookieToken = (request as any).cookies?.admin_access_token;
    if (cookieToken) return cookieToken;

    // 兼容 Authorization: Bearer header（旧客户端、移动端）
    const authHeader = request.headers.authorization;
    if (!authHeader?.startsWith('Bearer ')) return undefined;
    return authHeader.split(' ')[1];
  }

  private extractApiKey(request: Request): string | undefined {
    const header = request.headers['x-api-key'];
    if (typeof header === 'string' && header.length > 0) return header;
    return undefined;
  }
}
