import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from "@nestjs/common";
import { RequestStatus } from "../../../prisma/generated/client";
import { PrismaService } from "../../common/prisma/prisma.service";
import { validMediaUrls } from "../../common/service-fields";

@Injectable()
export class EngagementsService {
  constructor(private readonly prisma: PrismaService) {}

  async detail(id: string, actorId: string) {
    const request = await this.prisma.serviceRequest.findUnique({ where: { id }, include: { customer: { select: { id: true, fullName: true, avatarUrl: true, phone: true } }, service: true, offers: { include: { provider: { select: { id: true, fullName: true, avatarUrl: true, providerProfile: { select: { ratingAverage: true, isVerified: true } } } } }, orderBy: { createdAt: "asc" } }, stages: { orderBy: { sortOrder: "asc" } }, _count: { select: { offers: true, stages: true } } } });
    if (!request) throw new NotFoundException("request_not_found");
    const actorOffer = request.offers.find((offer) => offer.providerId === actorId && ["PENDING", "ACCEPTED"].includes(offer.status));
    const participates = request.customerId === actorId || Boolean(actorOffer);
    if (!participates || !request.offers.length) throw new ForbiddenException("request_access_denied");
    const canSeePhone = request.customerId === actorId || actorOffer?.status === "ACCEPTED";
    return { ...request, customer: { ...request.customer, phone: canSeePhone ? request.customer.phone : null }, offers: request.customerId === actorId ? request.offers : request.offers.filter(offer => offer.providerId === actorId) };
  }

  async cancel(id: string, actorId: string) {
    const request = await this.prisma.serviceRequest.findUnique({ where: { id } });
    if (!request) throw new NotFoundException("request_not_found");
    if (request.customerId !== actorId) throw new ForbiddenException("request_owner_only");
    if (["COMPLETED", "CANCELLED", "EXPIRED"].includes(request.status)) throw new ForbiddenException("invalid_status_transition");
    return this.prisma.serviceRequest.update({ where: { id }, data: { status: "CANCELLED" } });
  }

  private async stageAccess(requestId: string, actorId: string) {
    const request = await this.prisma.serviceRequest.findUnique({ where: { id: requestId }, include: { offers: { where: { status: "ACCEPTED" }, select: { providerId: true } } } });
    if (!request) throw new NotFoundException("request_not_found");
    if (request.customerId !== actorId && request.offers[0]?.providerId !== actorId) throw new ForbiddenException("request_participant_only");
    return request;
  }

  private async providerStageAccess(requestId: string, actorId: string) {
    const request = await this.stageAccess(requestId, actorId);
    if (request.offers[0]?.providerId !== actorId) throw new ForbiddenException("accepted_provider_only");
    if (!["ASSIGNED", "IN_PROGRESS"].includes(request.status)) throw new BadRequestException("request_not_in_progress");
    return request;
  }

  async addStage(requestId: string, actorId: string, body: { title?: string; description?: string; allowMedia?: boolean }) {
    await this.providerStageAccess(requestId, actorId); const title = body.title?.trim(); if (!title) throw new BadRequestException("stage_title_required");
    if (title.length > 200 || (body.description?.length ?? 0) > 2000) throw new BadRequestException("stage_field_too_long");
    const count = await this.prisma.requestStage.count({ where: { requestId } });
    return this.prisma.requestStage.create({ data: { requestId, title, description: body.description?.trim() || null, allowMedia: Boolean(body.allowMedia), sortOrder: count } });
  }

  async updateStage(requestId: string, stageId: string, actorId: string, body: { title?: string; description?: string; allowMedia?: boolean; completed?: boolean; completionNote?: string; mediaUrls?: string[] }) {
    await this.providerStageAccess(requestId, actorId); const stage = await this.prisma.requestStage.findFirst({ where: { id: stageId, requestId } }); if (!stage) throw new NotFoundException("stage_not_found");
    if ((body.title?.length ?? 0) > 200 || (body.description?.length ?? 0) > 2000 || (body.completionNote?.length ?? 0) > 2000) throw new BadRequestException("stage_field_too_long");
    if (body.mediaUrls && !stage.allowMedia) throw new BadRequestException("stage_media_disabled");
    return this.prisma.$transaction(async tx => {
      const updated = await tx.requestStage.update({ where: { id: stageId }, data: { ...(body.title !== undefined ? { title: body.title.trim() || stage.title } : {}), ...(body.description !== undefined ? { description: body.description.trim() || null } : {}), ...(body.allowMedia !== undefined ? { allowMedia: Boolean(body.allowMedia) } : {}), ...(body.completed !== undefined ? { completedAt: body.completed ? new Date() : null } : {}), ...(body.completionNote !== undefined ? { completionNote: body.completionNote.trim() || null } : {}), ...(body.mediaUrls ? { mediaUrls: validMediaUrls(body.mediaUrls, 6) } : {}) } });
      if (body.completed && !stage.completedAt) {
        const request = await tx.serviceRequest.update({ where: { id: requestId }, data: { status: "IN_PROGRESS" } });
        await tx.notification.create({ data: { userId: request.customerId, type: "STAGE_COMPLETED", title: "اكتملت مرحلة من خدمتك", body: stage.title, data: { requestId, stageId } } });
      }
      return updated;
    });
  }

  async complete(id: string, actorId: string) {
    const request = await this.prisma.serviceRequest.findUnique({
      where: { id },
      include: { offers: true },
    });
    if (!request) throw new NotFoundException("request_not_found");
    if (request.customerId !== actorId) throw new ForbiddenException("request_owner_only");
    if (request.status !== RequestStatus.IN_PROGRESS && request.status !== RequestStatus.ASSIGNED) {
      throw new ForbiddenException("invalid_status_transition");
    }
    return this.prisma.serviceRequest.update({
      where: { id },
      data: { status: RequestStatus.COMPLETED },
    });
  }
}
