import { ConflictException, ForbiddenException, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { AccountStatus, User, UserRole, WalletType } from '@prisma/client';
import bcrypt from 'bcrypt';
import { PrismaService } from '../database/prisma.service';
import { LoginDto } from './dto/login.dto';
import { RegisterDriverDto } from './dto/register-driver.dto';

@Injectable()
export class AuthService {
  constructor(
    private readonly jwtService: JwtService,
    private readonly prisma: PrismaService,
  ) {}

  async login(body: LoginDto, forcedRole?: UserRole | UserRole[]) {
    const filters: Array<{ email: string } | { phone: string }> = [];
    if (body.email) {
      filters.push({ email: body.email.trim().toLowerCase() });
    }
    if (body.phone) {
      filters.push({ phone: body.phone.trim() });
    }

    if (!filters.length) {
      throw new UnauthorizedException('Informe email ou telefone para entrar.');
    }

    const user = await this.prisma.user.findFirst({
      where: {
        OR: filters,
        ...(Array.isArray(forcedRole)
          ? { role: { in: forcedRole } }
          : { role: forcedRole ?? body.role }),
      },
    });

    if (!user) {
      throw new UnauthorizedException('Credenciais invalidas para este perfil.');
    }

    const matches = await bcrypt.compare(body.password, user.passwordHash);
    if (!matches) {
      throw new UnauthorizedException('Credenciais invalidas.');
    }

    if (user.role === UserRole.RESTAURANT) {
      if (user.status === 'PENDING') {
        throw new ForbiddenException('Cadastro de lojista em analise. Aguarde a aprovacao dos documentos para liberar o acesso.');
      }
      if (user.status === 'REJECTED') {
        throw new ForbiddenException('Cadastro de lojista reprovado. Revise a documentacao enviada e fale com o suporte.');
      }
      if (user.status === 'SUSPENDED') {
        throw new ForbiddenException('Acesso da loja suspenso. Procure o suporte administrativo.');
      }
    }

    if (user.role === UserRole.DRIVER) {
      if (user.status === 'PENDING') {
        throw new ForbiddenException('Cadastro de entregador em analise. Aguarde a validacao dos seus dados e documentos.');
      }
      if (user.status === 'REJECTED') {
        throw new ForbiddenException('Cadastro de entregador reprovado. Revise os dados enviados e fale com o suporte.');
      }
      if (user.status === 'SUSPENDED') {
        throw new ForbiddenException('Acesso do entregador suspenso. Procure o suporte administrativo.');
      }
    }

    return this.issueTokens(user);
  }

  async registerDriver(body: RegisterDriverDto) {
    const email = body.email.trim().toLowerCase();
    const phone = body.phone.trim();
    const existing = await this.prisma.user.findFirst({
      where: {
        OR: [{ email }, { phone }],
      },
    });

    if (existing) {
      throw new ConflictException('Ja existe uma conta com este e-mail ou telefone.');
    }

    const documentAlreadyUsed = await this.prisma.driver.findUnique({
      where: { documentNumber: body.documentNumber.trim() },
    });

    if (documentAlreadyUsed) {
      throw new ConflictException('Ja existe cadastro de entregador com este documento.');
    }

    const passwordHash = await bcrypt.hash(body.password, 12);

    const user = await this.prisma.user.create({
      data: {
        email,
        phone,
        passwordHash,
        role: UserRole.DRIVER,
        status: AccountStatus.PENDING,
      },
    });

    const driver = await this.prisma.driver.create({
      data: {
        userId: user.id,
        fullName: body.fullName.trim(),
        documentNumber: body.documentNumber.trim(),
        vehiclePlate: body.vehiclePlate.trim().toUpperCase(),
        vehicleModel: body.vehicleModel.trim(),
        pixKey: body.pixKey?.trim(),
        cnhUrl: body.cnhUrl?.trim(),
        vehicleDocumentUrl: body.vehicleDocumentUrl?.trim(),
        status: AccountStatus.PENDING,
      },
    });

    await this.prisma.wallet.create({
      data: {
        userId: user.id,
        driverId: driver.id,
        type: WalletType.DRIVER,
      },
    });

    return {
      ok: true,
      status: 'PENDING',
      message: 'Cadastro enviado. O acesso sera liberado apos a validacao dos dados do entregador e da moto.',
    };
  }

  async refresh(refreshToken: string) {
    try {
      const payload = await this.jwtService.verifyAsync(refreshToken);
      const user = await this.prisma.user.findUnique({ where: { id: payload.sub } });
      if (!user) {
        throw new UnauthorizedException('Usuario nao encontrado.');
      }
      return this.issueTokens(user);
    } catch (error) {
      if (error instanceof UnauthorizedException) {
        throw error;
      }
      throw new UnauthorizedException('Invalid refresh token');
    }
  }

  async me(userId: string) {
    const user = await this.prisma.user.findUnique({
      where: { id: userId },
      include: {
        customer: true,
        driver: true,
        restaurant: true,
        wallet: true,
      },
    });

    if (!user) {
      throw new UnauthorizedException('Usuario nao encontrado.');
    }

    return {
      id: user.id,
      role: user.role,
      email: user.email,
      phone: user.phone,
      status: user.status,
      customerId: user.customer?.id ?? null,
      driverId: user.driver?.id ?? null,
      restaurantId: user.restaurant?.id ?? null,
      walletId: user.wallet?.id ?? null,
    };
  }

  private async issueTokens(user: User) {
    const payload = {
      sub: user.id,
      role: user.role,
      email: user.email ?? undefined,
      phone: user.phone ?? undefined,
    };

    const accessToken = await this.jwtService.signAsync(payload);
    const refreshToken = await this.jwtService.signAsync(payload, { expiresIn: '30d' });

    return {
      accessToken,
      refreshToken,
      tokenType: 'Bearer',
      user: {
        id: user.id,
        role: user.role,
        email: user.email,
        phone: user.phone,
        status: user.status,
      },
    };
  }
}
