import {
  Injectable,
  UnauthorizedException,
  BadRequestException,
  Logger,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as bcrypt from 'bcrypt';
import { Seller } from '@/entities/seller.entity';
import { Merchant } from '@/entities/merchant.entity';
import { LoginDto, MerchantRegisterDto } from './dto/auth.dto';

// 内存缓存（生产环境应替换为 Redis）
const codeCache = new Map<string, { code: string; expiresAt: number }>();

@Injectable()
export class MerchantAuthService {
  private readonly logger = new Logger(MerchantAuthService.name);
  private readonly isDev = process.env.NODE_ENV === 'development';
  private readonly devCode = '123456';

  constructor(
    @InjectRepository(Seller)
    private sellerRepo: Repository<Seller>,
    @InjectRepository(Merchant)
    private merchantRepo: Repository<Merchant>,
    private jwtService: JwtService,
    private configService: ConfigService,
  ) {}

  // 发送验证码
  async sendCode(phone: string) {
    const code = Math.random().toString().slice(2, 8);
    await this.cacheCode(phone, code);
    this.logger.log(`商家验证码已发送至 ${phone}: ${code}`);
    return { message: '验证码已发送' };
  }

  // 注册（验证码方式）
  async register(dto: MerchantRegisterDto) {
    // 验证验证码
    await this.verifyCode(dto.phone, dto.code);

    const existing = await this.sellerRepo.findOne({
      where: { phone: dto.phone },
    });
    if (existing) {
      throw new BadRequestException('该手机号已注册');
    }

    const sellerData: Partial<Seller> = {
      phone: dto.phone,
      contactName: dto.contactName,
      email: dto.email,
    };

    if (dto.password) {
      sellerData.password = await bcrypt.hash(dto.password, 10);
    }

    const seller = this.sellerRepo.create(sellerData);
    await this.sellerRepo.save(seller);

    this.clearCachedCode(dto.phone);
    return this.generateToken(seller);
  }

  // 登录（支持验证码或密码）
  async login(dto: LoginDto) {
    if (!dto.code && !dto.password) {
      throw new BadRequestException('请输入验证码或密码');
    }

    if (dto.code) {
      const seller = await this.validateByCode(dto.phone, dto.code);
      this.clearCachedCode(dto.phone);
      return this.generateToken(seller);
    }

    const seller = await this.validateByPassword(dto.phone, dto.password!);
    return this.generateToken(seller);
  }

  async refresh(refreshToken: string) {
    try {
      const payload = await this.jwtService.verifyAsync(refreshToken, {
        secret: this.configService.get<string>('jwt.secret'),
      });

      const seller = await this.sellerRepo.findOne({ where: { id: payload.sub } });
      if (!seller) {
        throw new UnauthorizedException('商家账户不存在');
      }

      return this.generateToken(seller);
    } catch {
      throw new UnauthorizedException('刷新令牌无效');
    }
  }

  async findById(id: number) {
    return this.sellerRepo.findOne({ where: { id } });
  }

  // 验证码验证
  private async verifyCode(phone: string, code: string): Promise<void> {
    if (this.isDev && code === this.devCode) {
      return;
    }

    const cached = await this.getCachedCode(phone);
    if (!cached || cached !== code) {
      throw new BadRequestException('验证码错误或已过期');
    }
  }

  // 验证码登录验证
  private async validateByCode(phone: string, code: string): Promise<Seller> {
    await this.verifyCode(phone, code);

    const seller = await this.sellerRepo.findOne({ where: { phone } });
    if (!seller) {
      throw new UnauthorizedException('商家账户不存在');
    }
    if (seller.status !== 'active') {
      throw new UnauthorizedException('商家账户已被冻结或注销');
    }

    return seller;
  }

  // 密码登录验证
  private async validateByPassword(phone: string, password: string): Promise<Seller> {
    const seller = await this.sellerRepo
      .createQueryBuilder('seller')
      .where('seller.phone = :phone', { phone })
      .addSelect('seller.password')
      .getOne();

    if (!seller || !seller.password) {
      throw new UnauthorizedException('手机号或密码错误');
    }

    const isMatch = await bcrypt.compare(password, seller.password);
    if (!isMatch) {
      throw new UnauthorizedException('手机号或密码错误');
    }

    return seller;
  }

  // 验证码缓存方法
  private async cacheCode(phone: string, code: string): Promise<void> {
    // TODO: 生产环境替换为 Redis，设置5分钟过期
    const expiresAt = Date.now() + 5 * 60 * 1000;
    codeCache.set(phone, { code, expiresAt });
    this.logger.debug(`缓存商家验证码: ${phone} -> ${code}`);
  }

  private async getCachedCode(phone: string): Promise<string | null> {
    // TODO: 生产环境替换为 Redis
    const cached = codeCache.get(phone);
    if (!cached) return null;
    if (Date.now() > cached.expiresAt) {
      codeCache.delete(phone);
      return null;
    }
    return cached.code;
  }

  private async clearCachedCode(phone: string): Promise<void> {
    codeCache.delete(phone);
    this.logger.debug(`清除商家验证码: ${phone}`);
  }

  private async generateToken(seller: Seller) {
    const merchant = await this.merchantRepo.findOne({
      where: { sellerId: seller.id },
    });

    const payload = {
      sub: seller.id,
      phone: seller.phone,
      role: 'seller',
      merchantId: merchant?.id,
    };

    const accessToken = await this.jwtService.signAsync(payload);
    const refreshToken = await this.jwtService.signAsync(payload, {
      expiresIn: (this.configService.get<string>('jwt.refreshExpiresIn') ||
        '7d') as any,
    });

    return {
      accessToken,
      refreshToken,
      sellerInfo: {
        id: seller.id,
        phone: seller.phone,
        contactName: seller.contactName,
        email: seller.email,
        status: seller.status,
        merchantId: merchant?.id,
        merchantStatus: merchant?.status,
      },
    };
  }
}
