import * as Yup from "yup";
import { Request, Response } from "express";
import { getIO } from "../libs/socket";

import ListContactsService from "../services/ContactServices/ListContactsService";
import CreateContactService from "../services/ContactServices/CreateContactService";
import ShowContactService from "../services/ContactServices/ShowContactService";
import UpdateContactService from "../services/ContactServices/UpdateContactService";
import DeleteContactService from "../services/ContactServices/DeleteContactService";

import CheckContactNumber from "../services/WbotServices/CheckNumber";
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
import AppError from "../errors/AppError";

import {
  searchContactCache,
  insertContactsCache,
  escapeCharCache
} from "../helpers/ContactsCache";

import { off } from "process";
import GetContactService from "../services/ContactServices/GetContactService";
import ContactQueue from "../models/ContactQueues";

type IndexQuery = {
  searchParam: string;
  pageNumber: string;
  userId?:string;
};

type IndexGetContactQuery = {
  name: string;
  number: string;
};

interface ExtraInfo {
  name: string;
  value: string;
}
interface ContactData {
  name: string;
  number: string;
  email?: string;
  extraInfo?: ExtraInfo[];
  queueIds?: number[];
}

export const index = async (req: Request, res: Response): Promise<Response> => {
  let { searchParam, pageNumber, userId } = req.query as IndexQuery;

  console.log("PAGE NUMBER CONTACT: ", pageNumber);

  if (pageNumber === undefined || pageNumber.trim().length == 0) {
    pageNumber = "1";
  }

  // TEST DEL
  if (searchParam && searchParam.trim().length > 0 && process.env.CACHE) {
    try {
      const offset = 20 * (+pageNumber - 1);

      searchParam = searchParam.replace(/\s+/g, " ").trim().toLowerCase();

      const data = await searchContactCache(searchParam, offset, 20);

      if (data) {
        console.log("QUERY CONTACTS FROM CACHE SEARCH PARAM: ", searchParam);

        console.log("QUERY CONTACTS FROM CACHE QUERY LENGTH: ", data.length);

        return res.json({
          contacts: data,
          count: data.length,
          hasMore: data.length > 0 ? true : false
        });
      }
    } catch (error) {
      console.log(
        "There was an error on search ContactController.ts search cache: ",
        error
      );
    }
  } 

  const { contacts, count, hasMore } = await ListContactsService({
    searchParam,
    pageNumber,
    userId
  });

  return res.json({ contacts, count, hasMore });
};

export const getContact = async (
  req: Request,
  res: Response
): Promise<Response> => {
  const { name, number } = req.body as IndexGetContactQuery;

  const contact = await GetContactService({
    name,
    number
  });

  return res.status(200).json(contact);
};

export const store = async (req: Request, res: Response): Promise<Response> => {
  const newContact: ContactData = req.body;
  newContact.number = newContact.number.replace("-", "").replace(" ", "");

  const schema = Yup.object().shape({
    name: Yup.string().required(),
    number: Yup.string()
      .required()
      .matches(/^\d+$/, "Invalid number format. Only numbers is allowed.")
    // .matches(/^55\d+$/, "The number must start with 55.")
  });

  try {
    await schema.validate(newContact);
  } catch (err: any) {
    throw new AppError(err.message);
  }

  newContact.number = addStartPhoneNumber(newContact.number);

  const validNumber = await CheckIsValidContact(newContact.number);

  if (!validNumber) {
    throw new AppError("ERR_WAPP_CHECK_CONTACT");
  }

  const profilePicUrl = await GetProfilePicUrl(validNumber);

  let name = newContact.name;
  let number = validNumber;
  let email = newContact.email;
  let extraInfo = newContact.extraInfo;

  const contact = await CreateContactService({
    name,
    number,
    email,
    profilePicUrl: profilePicUrl,
    extraInfo,
    queueIds: newContact?.queueIds
  });

  const io = getIO();
  io.emit("contact", {
    action: "create",
    contact
  });

  return res.status(200).json(contact);
};

export const show = async (req: Request, res: Response): Promise<Response> => {
  const { contactId } = req.params;

  const contact = await ShowContactService(contactId);

  return res.status(200).json(contact);
};

export const update = async (
  req: Request,
  res: Response
): Promise<Response> => {
  const contactData: ContactData = req.body;

  const schema = Yup.object().shape({
    name: Yup.string(),
    number: Yup.string().matches(
      /^\d+$/,
      "Invalid number format. Only numbers is allowed."
    )
    // .matches(/^55\d+$/, "The number must start with 55.")
  });

  try {
    await schema.validate(contactData);
  } catch (err: any) {
    throw new AppError(err.message);
  }

  contactData.number = addStartPhoneNumber(contactData.number);

  await CheckIsValidContact(contactData.number);

  const { contactId } = req.params;

  const contact = await UpdateContactService({ contactData, contactId });

  const io = getIO();
  io.emit("contact", {
    action: "update",
    contact
  });

  return res.status(200).json(contact);
};

export const remove = async (
  req: Request,
  res: Response
): Promise<Response> => {
  const { contactId } = req.params;

  await DeleteContactService(contactId);

  await ContactQueue.destroy({ where: { contactId } });

  const io = getIO();
  io.emit("contact", {
    action: "delete",
    contactId
  });

  return res.status(200).json({ message: "Contact deleted" });
};

export const contacsBulkInsertOnQueue = async (
  req: Request,
  res: Response
): Promise<Response> => {
  // console.log('THE BODY: ', req.body)

  const {
    adminId,
    identifier,
    queueStatus,
    file,
    contacts_inserted,
    campaign
  } = req.body;

  const io = getIO();
  io.emit("contactsBulkInsertOnQueueStatus", {
    action: "update",
    insertOnQueue: {
      adminId: adminId,
      identifier: identifier,
      queueStatus: queueStatus,
      file: file,
      campaign
    }
  });

  if (process.env.CACHE && contacts_inserted) {
    await insertContactsCache(contacts_inserted);
  }

  return res.status(200).json({ message: "ok" });
};

function addStartPhoneNumber(phoneNumber: string) {
  const regex = /^55/;

  if (!regex.test(phoneNumber)) {
    phoneNumber = "55" + phoneNumber;
  }

  return phoneNumber;
}
