import { BadRequestException, Injectable } from '@nestjs/common';
import { CreateProjectDto } from './dto/create-project.dto';
import { UpdateProjectDto } from './dto/update-project.dto';
import { InjectModel } from '@nestjs/mongoose';
import { Project, ProjectDocument } from './schemas/project.schema';
import { Model } from 'mongoose';
import { User, UserDocument } from '../users/schemas/user.schema';
import { Role } from '../users/roles/role.enum';

@Injectable()
export class ProjectService {
  constructor(
    @InjectModel(Project.name) private projectModel: Model<ProjectDocument>,
    @InjectModel(User.name) private userModel: Model<UserDocument>,
  ) {}

  async createWithoutAuth(createProjectDto: CreateProjectDto) {
    const { contact, ...projectData } = createProjectDto;
    const creatorId = await this.resolveGuestCreator(contact);

    return this.projectModel.create({
      ...projectData,
      ...(creatorId ? { creator: creatorId } : {}),
    });
  }

  private async resolveGuestCreator(
    contact: CreateProjectDto['contact'],
  ): Promise<string | null> {
    const email = contact?.email?.trim().toLowerCase();
    if (!email) return null;

    const existing = await this.userModel
      .findOne({ email })
      .select('password')
      .lean();

    if (existing?.password) {
      throw new BadRequestException('EMAIL_ALREADY_REGISTERED');
    }

    const postcode =
      contact.postcode !== undefined && contact.postcode !== null
        ? Number(contact.postcode) || undefined
        : undefined;

    const user = await this.userModel.findOneAndUpdate(
      { email },
      {
        $setOnInsert: {
          email,
          firstName: contact.firstName,
          lastName: contact.lastName,
          phone: contact.phone,
          location: contact.location,
          postcode,
          role: Role.User,
        },
      },
      { upsert: true, new: true },
    );

    return user._id;
  }

  async create(createProjectDto: CreateProjectDto, user: UserDocument) {
    return this.projectModel.create({
      ...createProjectDto,
      creator: user._id,
    });
  }

  findAll(user: UserDocument) {
    const filter: Record<string, unknown> = { quote: { $exists: false } };

    if (user.role !== Role.Admin) {
      filter.creator = user._id;
    }

    return this.projectModel.find(filter).exec();
  }

  findOne(_id: string) {
    return this.projectModel
      .findOne({ _id })
      .populate({
        path: 'quote',
        populate: {
          path: 'client',
          select: [
            '_id',
            'firstName',
            'lastName',
            'postcode',
            'location',
            'email',
            'phone',
          ],
        },
      })
      .exec();
  }

  async update(_id: string, updateProjectDto: UpdateProjectDto) {
    const newProject = await this.projectModel
      .findOneAndUpdate({ _id }, { ...updateProjectDto }, { new: true })
      .exec();

    if (!newProject) {
      throw new BadRequestException('Project not found!');
    }

    return newProject;
  }

  async remove(_id: string) {
    await this.projectModel.deleteOne({ _id });
    return { success: true };
  }

  async removeMany(ids: string[]) {
    if (!Array.isArray(ids)) {
      throw new BadRequestException('field ids not array');
    }

    await this.projectModel.deleteMany({ _id: ids });
    return { success: true };
  }
}
