import { FastifyReply, FastifyRequest } from "fastify";
import prisma from "../../utils/prisma";
import { IdParamsSchema } from "../../utils/schema";
import {
  CompanyActiveSchema,
  CompanyContributorSchema,
  CompanySchema,
  EmailSchema,
  MassCitiesSchema,
  MassCompaniesSchema,
} from "./schema";
import { $Enums } from "@prisma/client";
import { mail } from "../../utils/mail";
import { MinioDocumentSchema } from "../minio/schema";
import { v4 as uuid } from "uuid";
import { getPresignedUrl, minioClient } from "../../utils/minio";
import { bucketName } from "../../utils/consts";

//-------------------------------------------------------------------------------

export async function getCompanies(req: FastifyRequest, reply: FastifyReply) {
  const companies = await prisma.company.findMany({
    select: {
      id: true,
      name: true,
      email: true,
      legalForm: true,
      city: true,
      turnover: true,
      nEmployees: true,
      activities: true,
      activitiesFamilies: true,
      active: true,
      verified: true,
      contributor: true,
      createdAt: true,
    },
    orderBy: {
      name: "asc",
    },
  });

  return reply.code(200).send(companies);
}

//-------------------------------------------------------------------------------

export async function createCompany(
  req: FastifyRequest<{ Body: CompanySchema }>,
  reply: FastifyReply
) {
  const data = req.body;

  const city = await prisma.city.findUnique({
    where: {
      id: data.cityId,
    },
  });

  if (!city) {
    return reply.code(400).send({
      message: "La ville n'existe pas",
    });
  }

  if (data.contactPositionId) {
    const position = await prisma.position.findUnique({
      where: {
        id: data.contactPositionId,
      },
    });

    if (!position) {
      return reply.code(400).send({
        message: "La fonction n'existe pas",
      });
    }
  }

  const turnover = await prisma.turnover.findUnique({
    where: {
      id: data.turnoverId,
    },
  });

  if (!turnover) {
    return reply.code(400).send({
      message: "Le chiffre d'affaires n'existe pas",
    });
  }
  const nEmployees = await prisma.nEmployees.findUnique({
    where: {
      id: data.nEmployeesId,
    },
  });

  if (!nEmployees) {
    return reply.code(400).send({
      message: "L'effectif n'existe pas",
    });
  }

  const company = await prisma.company.create({
    data: {
      active: data.active,
      contributor: data.contributor,

      name: data.name,
      legalForm: data.legalForm,

      cityId: data.cityId,
      address: data.address,
      phoneNumber: data.phoneNumber,
      fax: data.fax,
      email: data.email.toLowerCase(),

      website: data.website,
      linkedin: data.linkedin,
      facebook: data.facebook,

      contactFirstName: data.contactFirstName,
      contactLastName: data.contactLastName,
      contactEmail: data.contactEmail,
      contactPositionId: data.contactPositionId,
      contactLinkedin: data.contactLinkedin,
      contactFacebook: data.contactFacebook,

      businessLicense: data.businessLicense,
      numRC: data.numRC,
      numICE: data.numICE,
      capital: data.capital,
      turnoverId: data.turnoverId,
      nEmployeesId: data.nEmployeesId,

      activitiesFamilies: data.activitiesFamilies,
      activities: data.activities,
      importCountries: data.importCountries,
      exportCountries: data.exportCountries,

      verified: true,
    },
    select: {
      id: true,
      name: true,
      email: true,
      legalForm: true,
      city: true,
      turnover: true,
      nEmployees: true,
      activities: true,
      activitiesFamilies: true,
      active: true,
      verified: true,
      contributor: true,
      createdAt: true,
    },
  });

  return reply.code(200).send(company);
}

//-------------------------------------------------------------------------------

export async function getCompany(
  req: FastifyRequest<{ Params: IdParamsSchema }>,
  reply: FastifyReply
) {
  const id = req.params.id;
  const company = await prisma.company.findUnique({
    where: {
      id: id,
    },
    select: {
      id: true,
      name: true,
      legalForm: true,

      city: true,
      address: true,
      phoneNumber: true,
      fax: true,
      email: true,

      website: true,
      linkedin: true,
      facebook: true,

      contactFirstName: true,
      contactLastName: true,
      contactEmail: true,

      contactPosition: true,
      contactLinkedin: true,
      contactFacebook: true,

      businessLicense: true,
      numRC: true,
      numICE: true,
      capital: true,

      turnover: true,
      nEmployees: true,

      activitiesFamilies: true,
      activities: true,
      importCountries: true,
      exportCountries: true,

      active: true,
      verified: true,
      contributor: true,

      createdAt: true,

      users: {
        select: {
          id: true,
          civility: true,
          firstName: true,
          lastName: true,
          email: true,
          active: true,
          position: true,
          company: {
            select: {
              id: true,
              name: true,
            },
          },
          createdAt: true,
        },
        orderBy: {
          createdAt: "desc",
        },
      },
    },
  });

  if (!company) {
    return reply.code(404).send({
      message: "Cette entreprise n'existe pas",
    });
  }

  return reply.code(200).send(company);
}

//-------------------------------------------------------------------------------

export async function editCompany(
  req: FastifyRequest<{ Params: IdParamsSchema; Body: CompanySchema }>,
  reply: FastifyReply
) {
  const id = req.params.id;
  const data = req.body;

  const company = await prisma.company.findUnique({
    where: {
      id: id,
    },
  });

  if (!company) {
    return reply.code(400).send({
      message: "Cette entreprise n'existe pas",
    });
  }

  const city = await prisma.city.findUnique({
    where: {
      id: data.cityId,
    },
  });

  if (!city) {
    return reply.code(400).send({
      message: "La ville n'existe pas",
    });
  }

  if (data.contactPositionId) {
    const position = await prisma.position.findUnique({
      where: {
        id: data.contactPositionId,
      },
    });

    if (!position) {
      return reply.code(400).send({
        message: "La fonction n'existe pas",
      });
    }
  }

  const turnover = await prisma.turnover.findUnique({
    where: {
      id: data.turnoverId,
    },
  });

  if (!turnover) {
    return reply.code(400).send({
      message: "Le chiffre d'affaires n'existe pas",
    });
  }
  const nEmployees = await prisma.nEmployees.findUnique({
    where: {
      id: data.nEmployeesId,
    },
  });

  if (!nEmployees) {
    return reply.code(400).send({
      message: "L'effectif n'existe pas",
    });
  }

  const newCompany = await prisma.company.update({
    where: {
      id: id,
    },
    data: {
      active: data.active,
      contributor: data.contributor,

      name: data.name,
      legalForm: data.legalForm,

      cityId: data.cityId,
      address: data.address,
      phoneNumber: data.phoneNumber,
      fax: data.fax,
      email: data.email.toLowerCase(),

      website: data.website,
      linkedin: data.linkedin,
      facebook: data.facebook,

      contactFirstName: data.contactFirstName,
      contactLastName: data.contactLastName,
      contactEmail: data.contactEmail,
      contactPositionId: data.contactPositionId,
      contactLinkedin: data.contactLinkedin,
      contactFacebook: data.contactFacebook,

      businessLicense: data.businessLicense,
      numRC: data.numRC,
      numICE: data.numICE,
      capital: data.capital,
      turnoverId: data.turnoverId,
      nEmployeesId: data.nEmployeesId,

      activitiesFamilies: data.activitiesFamilies,
      activities: data.activities,
      importCountries: data.importCountries,
      exportCountries: data.exportCountries,
    },
    select: {
      id: true,
      name: true,
      email: true,
      legalForm: true,
      city: true,
      turnover: true,
      nEmployees: true,
      activities: true,
      activitiesFamilies: true,
      active: true,
      verified: true,
      contributor: true,
      createdAt: true,
    },
  });

  return reply.code(200).send(newCompany);
}

//-------------------------------------------------------------------------------

export async function editCompanyActive(
  req: FastifyRequest<{ Params: IdParamsSchema; Body: CompanyActiveSchema }>,
  reply: FastifyReply
) {
  const id = req.params.id;
  const data = req.body;

  const company = await prisma.company.findUnique({
    where: {
      id: id,
    },
  });

  if (!company) {
    return reply.code(404).send({
      message: "Cette entreprise n'existe pas",
    });
  }

  const newCompany = await prisma.company.update({
    where: { id: id },
    data: {
      active: data.active,
    },
  });

  return reply.code(200).send({ active: newCompany.active });
}

//-------------------------------------------------------------------------------

export async function editCompanyContributor(
  req: FastifyRequest<{
    Params: IdParamsSchema;
    Body: CompanyContributorSchema;
  }>,
  reply: FastifyReply
) {
  const id = req.params.id;
  const data = req.body;

  const company = await prisma.company.findUnique({
    where: {
      id: id,
    },
  });

  if (!company) {
    return reply.code(404).send({
      message: "Cette entreprise n'existe pas",
    });
  }

  const newCompany = await prisma.company.update({
    where: { id: id },
    data: {
      contributor: data.contributor,
    },
  });

  return reply.code(200).send({ contributor: newCompany.contributor });
}

//-------------------------------------------------------------------------------

export async function editCompanyVerified(
  req: FastifyRequest<{
    Params: IdParamsSchema;
  }>,
  reply: FastifyReply
) {
  const id = req.params.id;

  const company = await prisma.company.findUnique({
    where: {
      id: id,
      verified: false,
    },
  });

  if (!company) {
    return reply.code(404).send({
      message: "Cette entreprise en attente n'existe pas",
    });
  }

  const newCompany = await prisma.company.update({
    where: { id: id },
    data: {
      verified: true,
    },
  });

  return reply.code(200).send({ verified: newCompany.verified });
}

//-------------------------------------------------------------------------------

export async function addMassCities(
  req: FastifyRequest<{ Body: MassCitiesSchema }>,
  reply: FastifyReply
) {
  const data = req.body;

  const promises = data.map(async (c) => {
    const city = await prisma.city.findFirst({ where: { name: c } });
    if (!city) {
      console.log(c);
      await prisma.city.create({ data: { name: c } });
    }
  });
  await Promise.all(promises);

  return reply.code(200).send({});
}

//-------------------------------------------------------------------------------

export async function addMassPositions(
  req: FastifyRequest<{ Body: MassCitiesSchema }>,
  reply: FastifyReply
) {
  const data = req.body;

  const promises = data.map(async (p) => {
    const position = await prisma.position.findFirst({ where: { name: p } });
    if (!position) {
      console.log(p);
      await prisma.position.create({ data: { name: p } });
    }
  });
  await Promise.all(promises);

  return reply.code(200).send({});
}

// ------------------------------------------------------------------------------------
export async function addMassCompanies(
  req: FastifyRequest<{ Body: MassCompaniesSchema }>,
  reply: FastifyReply
) {
  const data = req.body; //.slice(0, 10);

  // cities -------------------------------------------------------------------------
  const cities: string[] = [];
  data.map((c) => {
    if (!cities.includes(c.cityName)) {
      cities.push(c.cityName);
    }
  });
  const citiesObject: { name: string; id: string }[] = [];
  const promisesCities = cities.map(async (c) => {
    const cityPrisma = await prisma.city.findFirst({
      where: { name: c },
    });
    if (!cityPrisma) {
      return reply.code(200).send({ message: "city doesnt exist", city: c });
    } else {
      citiesObject.push({ name: cityPrisma.name, id: cityPrisma.id });
    }
  });
  await Promise.all(promisesCities);
  // positions -------------------------------------------------------------------------
  const positions: string[] = [];
  data.map((c) => {
    if (!positions.includes(c.contactPositionName)) {
      positions.push(c.contactPositionName);
    }
  });
  const positionsObject: { name: string; id: string }[] = [];
  const promisesPos = positions.map(async (p) => {
    const positionPrisma = await prisma.position.findFirst({
      where: { name: p },
    });
    if (!positionPrisma) {
      return reply
        .code(200)
        .send({ message: "position doesnt exist", position: p });
    } else {
      positionsObject.push({
        name: positionPrisma.name,
        id: positionPrisma.id,
      });
    }
  });
  await Promise.all(promisesPos);
  // turnovers -------------------------------------------------------------------------
  const turnovers: string[] = [];
  data.map((c) => {
    if (!turnovers.includes(c.turnoverName)) {
      turnovers.push(c.turnoverName);
    }
  });
  const turnoversObject: { name: string; id: string | null }[] = [];
  const promisesTurn = turnovers.map(async (t) => {
    if (t === "") {
      turnoversObject.push({
        name: "",
        id: null,
      });
    } else {
      const turnoverPrisma = await prisma.turnover.findFirst({
        where: { name: t },
      });
      if (!turnoverPrisma) {
        return reply
          .code(200)
          .send({ message: "turnover doesnt exist", turnover: t });
      } else {
        turnoversObject.push({
          name: turnoverPrisma.name,
          id: turnoverPrisma.id,
        });
      }
    }
  });
  await Promise.all(promisesTurn);

  // turnovers -------------------------------------------------------------------------
  const nEmployees: string[] = [];
  data.map((c) => {
    if (!nEmployees.includes(c.nEmployeesName)) {
      nEmployees.push(c.nEmployeesName);
    }
  });
  const nEmployeesObject: { name: string; id: string | null }[] = [];
  const promisesEffectif = nEmployees.map(async (t) => {
    if (t === "") {
      nEmployeesObject.push({
        name: "",
        id: null,
      });
    } else {
      const nEmployeesPrisma = await prisma.nEmployees.findFirst({
        where: { name: t },
      });
      if (!nEmployeesPrisma) {
        return reply
          .code(200)
          .send({ message: "nEmployees doesnt exist", nEmployees: t });
      } else {
        nEmployeesObject.push({
          name: nEmployeesPrisma.name,
          id: nEmployeesPrisma.id,
        });
      }
    }
  });
  await Promise.all(promisesEffectif);

  //-----------------------------------------------------------------------------------

  const companies = data.map(async (c) => {
    const city = citiesObject.find((city) => city.name === c.cityName);
    const position = positionsObject.find(
      (position) => position.name === c.contactPositionName
    );
    const tunover = turnoversObject.find(
      (tunover) => tunover.name === c.turnoverName
    );
    const nEmployees = nEmployeesObject.find(
      (nEmployees) => nEmployees.name === c.nEmployeesName
    );

    await prisma.company.create({
      data: {
        active: true,
        contributor: true,

        name: c.name,
        legalForm: c.legalFormFormated,

        cityId: city?.id,
        address: c.address,
        phoneNumber: `${c.phoneNumber}`,
        fax: `${c.fax}`,
        email: c.email,

        website: c.website,
        linkedin: c.linkedin,
        facebook: c.facebook,

        contactFirstName: c.contactFirstName,
        contactLastName: c.contactLastName,
        contactEmail: c.contactEmail,
        contactPositionId: position?.id,
        contactLinkedin: c.contactLinkedin,
        contactFacebook: c.contactFacebook,

        businessLicense: `${c.businessLicense}`,
        numRC: `${c.numRC}`,
        numICE: `${c.numICE}`,
        capital: parseInt(`${c.capital}`),
        turnoverId: tunover?.id,
        nEmployeesId: nEmployees?.id,

        activitiesFamilies: [c.activitiesFamilies],
        activities: [c.activities],
        importCountries: [],
        exportCountries: [],
      },
    });
  });
  await Promise.all(companies);
  return reply.code(200).send({});
}

// -------------------------------------------------------------------------

export async function uploadEmailAttachment(
  req: FastifyRequest<{ Body: MinioDocumentSchema }>,
  reply: FastifyReply
) {
  const data = req.body;
  const buffer = await data.document.toBuffer();
  const ext = data.document.filename.split(".").pop();
  const mimetype = data.document.mimetype;
  const fileName = "emails-attachments/" + uuid() + "." + ext;
  await minioClient.putObject(bucketName, fileName, buffer, undefined, {
    "Content-Type": mimetype,
  });
  const presignedAttachment = await getPresignedUrl(fileName);
  return reply.code(200).send({
    name: data.document.filename,
    attachment: fileName,
    presignedAttachment: presignedAttachment,
  });
}

// -------------------------------------------------------------------------

export async function sendEmail(
  req: FastifyRequest<{ Body: EmailSchema }>,
  reply: FastifyReply
) {
  const data = req.body;
  const companies = await prisma.company.findMany({
    where: {
      id: { in: data.companies },
    },
    select: { email: true },
  });

  const emails = companies
    .map((company) => company.email)
    .filter((email) => email && email !== "");

  const attachments = data.attachments.map((attachment) => ({
    filename: attachment.name,
    path: attachment.presignedAttachment,
  }));

  try {
    await mail.sendMail({
      from: process.env.EMAIL_HOST_USER,
      to: emails.join(","),
      subject: data.subject,
      html: data.body,
      attachments,
    });
  } catch {}

  return reply.code(200).send({});
}
