import {
  Controller,
  Get,
  Query,
  Headers,
  UnauthorizedException,
  ParseIntPipe,
  DefaultValuePipe,
  Logger,
} from '@nestjs/common';
import { GetMyReferralInfoUseCase } from '../../../application/use-cases/get-my-referral-info.use-case';
import { ValidateReferralCodeUseCase } from '../../../application/use-cases/validate-referral-code.use-case';
import { GetReferralListUseCase } from '../../../application/use-cases/get-referral-list.use-case';
import { GetMyUserReferralInfoUseCase } from '../../../application/use-cases/get-my-user-referral-info.use-case';
import { GetMyCircleUseCase } from '../../../application/use-cases/get-my-circle.use-case';
import { UserPointRepository } from '../../../infrastructure/repositories/user-point.repository';
import * as jwt from 'jsonwebtoken';

/**
 * User-facing referral endpoints (JWT required via Kong).
 *
 * Tenant-level (B2B):
 *   GET /me           → tenant referral code + stats
 *   GET /me/referrals → tenant-level direct referral list
 *   GET /me/rewards   → tenant credit rewards
 *
 * User-level / personal circle (C2C):
 *   GET /me/user   → personal code + points balance
 *   GET /me/circle → personal circle members (level-1 invitees)
 *   GET /me/points → points balance + transaction history
 *
 * Public:
 *   GET /validate?code=... → validate any referral code
 */
@Controller('api/v1/referral')
export class ReferralController {
  private readonly logger = new Logger(ReferralController.name);

  constructor(
    private readonly getMyReferralInfo: GetMyReferralInfoUseCase,
    private readonly validateCode: ValidateReferralCodeUseCase,
    private readonly getReferralList: GetReferralListUseCase,
    private readonly getMyUserReferralInfo: GetMyUserReferralInfoUseCase,
    private readonly getMyCircle: GetMyCircleUseCase,
    private readonly pointRepo: UserPointRepository,
  ) {}

  // ── Tenant-level (B2B) ──────────────────────────────────────────────────

  @Get('me')
  async getMe(@Headers('authorization') auth: string) {
    const { tenantId, userId } = this.extractJwt(auth);
    return this.getMyReferralInfo.execute(tenantId, userId);
  }

  @Get('me/referrals')
  async getMyReferrals(
    @Headers('authorization') auth: string,
    @Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit: number,
    @Query('offset', new DefaultValuePipe(0), ParseIntPipe) offset: number,
  ) {
    const { tenantId } = this.extractJwt(auth);
    return this.getReferralList.getReferrals(tenantId, Math.min(limit, 100), offset);
  }

  @Get('me/rewards')
  async getMyRewards(
    @Headers('authorization') auth: string,
    @Query('status') status: 'PENDING' | 'APPLIED' | 'EXPIRED' | undefined,
    @Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit: number,
    @Query('offset', new DefaultValuePipe(0), ParseIntPipe) offset: number,
  ) {
    const { tenantId } = this.extractJwt(auth);
    return this.getReferralList.getRewards(tenantId, status, Math.min(limit, 100), offset);
  }

  // ── User-level / personal circle (C2C) ─────────────────────────────────

  /** GET /me/user — personal code, shareUrl, circle size, points balance */
  @Get('me/user')
  async getMyUserInfo(@Headers('authorization') auth: string) {
    const { userId } = this.extractJwt(auth);
    return this.getMyUserReferralInfo.execute(userId);
  }

  /** GET /me/circle — personal circle members (level-1 invitees) */
  @Get('me/circle')
  async getMyCircleMembers(
    @Headers('authorization') auth: string,
    @Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit: number,
    @Query('offset', new DefaultValuePipe(0), ParseIntPipe) offset: number,
  ) {
    const { userId } = this.extractJwt(auth);
    return this.getMyCircle.execute(userId, Math.min(limit, 100), offset);
  }

  /** GET /me/points — points balance + recent transactions */
  @Get('me/points')
  async getMyPoints(
    @Headers('authorization') auth: string,
    @Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit: number,
    @Query('offset', new DefaultValuePipe(0), ParseIntPipe) offset: number,
  ) {
    const { userId } = this.extractJwt(auth);
    const [balance, txns] = await Promise.all([
      this.pointRepo.getBalance(userId),
      this.pointRepo.getTransactions(userId, Math.min(limit, 100), offset),
    ]);
    return { balance, transactions: txns };
  }

  // ── Public ───────────────────────────────────────────────────────────────

  @Get('validate')
  async validate(@Query('code') code: string) {
    return this.validateCode.execute(code ?? '');
  }

  // ── Helper ───────────────────────────────────────────────────────────────

  private extractJwt(auth: string): { tenantId: string; userId: string } {
    if (!auth?.startsWith('Bearer ')) throw new UnauthorizedException('Missing authorization header');
    const token = auth.slice(7);
    try {
      const payload = jwt.verify(token, process.env.JWT_SECRET || 'dev-secret') as any;
      return { tenantId: payload.tenantId, userId: payload.sub };
    } catch {
      throw new UnauthorizedException('Invalid JWT');
    }
  }
}
