import { Request, Response } from "express";
import { getIO } from "../libs/socket";

import CreateTicketService from "../services/TicketServices/CreateTicketService";
import DeleteTicketService from "../services/TicketServices/DeleteTicketService";
import ListTicketsService from "../services/TicketServices/ListTicketsService";
import ShowTicketService from "../services/TicketServices/ShowTicketService";
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService";
import ShowStatusChatEndService from "../services/StatusChatEndService/ShowStatusChatEndService";

import CreateSchedulingNotifyService from "../services/SchedulingNotifyServices/CreateSchedulingNotifyService";
import ListSchedulingNotifyContactService from "../services/SchedulingNotifyServices/ListSchedulingNotifyContactService";

import { isScheduling } from "../helpers/CheckSchedulingReminderNotify";

import ptBR from "date-fns/locale/pt-BR";
import { splitDateTime } from "../helpers/SplitDateTime";
import format from "date-fns/format";

import ListTicketsServiceCache from "../services/TicketServices/ListTicketServiceCache";

import { searchTicketCache, loadTicketsCache } from "../helpers/TicketCache";
import { Op } from "sequelize";

type IndexQuery = {
  searchParam: string;
  pageNumber: string;
  status: string;
  date: string;
  showAll: string;
  withUnreadMessages: string;
  queueIds: string;
  unlimited?: string;
  searchParamContent?: string;
};

interface TicketData {
  contactId: number;
  status: string;
  queueId: number;
  userId: number;
  whatsappId?: string | number;
  msg?: string;
  transfer?: boolean | undefined;
  fromMe?: boolean;
}

import ListStatusChatEndService from "../services/StatusChatEndService/ListStatusChatEndService";
import Ticket from "../models/Ticket";
import ShowUserServiceReport from "../services/UserServices/ShowUserServiceReport";
import TicketEmiterSumOpenClosedByUser from "../helpers/OnlineReporEmiterInfoByUser";
import CountTicketService from "../services/TicketServices/CountTicketService";
import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
import ShowUserService from "../services/UserServices/ShowUserService";
import axios from "axios";
import User from "../models/User";
import CheckContactOpenTickets from "../helpers/CheckContactOpenTickets";
import GetDefaultWhatsApp from "../helpers/GetDefaultWhatsApp";
import { getWbot } from "../libs/wbot";
import endPointQuery from "../helpers/old_EndPointQuery";
import Contact from "../models/Contact";
import BotIsOnQueue from "../helpers/BotIsOnQueue";
import { setMessageAsRead } from "../helpers/SetMessageAsRead";
import { getSettingValue } from "../helpers/WhaticketSettings";
import ListWhatsAppsForQueueService from "../services/WhatsappService/ListWhatsAppsForQueueService";
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
import Whatsapp from "../models/Whatsapp";
import AppError from "../errors/AppError";
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService";
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
import CreateContactService from "../services/ContactServices/CreateContactService";
import { botSendMessage } from "../services/WbotServices/wbotMessageListener";
import WhatsappQueue from "../models/WhatsappQueue";

export const index = async (req: Request, res: Response): Promise<Response> => {
  const {
    pageNumber,
    status,
    date,
    searchParam,
    showAll,
    queueIds: queueIdsStringified,
    withUnreadMessages,
    unlimited,
    searchParamContent
  } = req.query as IndexQuery;

  const userId = req.user.id;

  let queueIds: number[] = [];

  if (queueIdsStringified && queueIdsStringified.trim().length > 0) {
    queueIds = JSON.parse(queueIdsStringified);
  }

  const { tickets, count, hasMore } = await ListTicketsService({
    searchParam,
    pageNumber,
    status,
    date,
    showAll,
    userId,
    queueIds,
    withUnreadMessages,
    unlimited,
    searchParamContent
  });

  return res.status(200).json({ tickets, count, hasMore });
};

export const remoteTicketCreation = async (
  req: Request,
  res: Response
): Promise<Response> => {
  const { contact_from, contact_to, msg, contact_name }: any = req.body;

  const validate = ["contact_from", "contact_to", "msg"];
  const validateOnlyNumber = ["contact_from", "contact_to"];

  for (let prop of validate) {
    if (!req.body[prop])
      return res
        .status(400)
        .json({ error: `Property '${prop}' is undefined.` });

    if (validateOnlyNumber.includes(prop)) {
      if (!/^\d+$/.test(req.body[prop])) {
        return res
          .status(400)
          .json({ error: `The property '${prop}' must be a number` });
      }
    }
  }

  const whatsapp = await Whatsapp.findOne({
    where: { number: contact_from, status: "CONNECTED" }
  });

  if (whatsapp) {
    const { id: whatsappId, number, status } = whatsapp;

    const queue: any = await WhatsappQueue.findOne({
      where: { whatsappId },
      attributes: ["queueId"]
    });

    const { queueId } = queue;

    // const validNumber = await CheckIsValidContact(contact_to, true);
    const validNumber = contact_to;

    if (validNumber) {
      let contact = await Contact.findOne({ where: { number: validNumber } });

      if (!contact) {
        // const profilePicUrl = await GetProfilePicUrl(validNumber);

        contact = await CreateContactService({
          name: contact_name ? contact_name : contact_to,
          number: validNumber
          // profilePicUrl
        });

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

      const { id: contactId } = contact;

      const botInfo = await BotIsOnQueue("botqueue");

      let ticket = await Ticket.findOne({
        where: {
          [Op.or]: [
            { contactId, status: "queueChoice" },
            { contactId, status: "open", userId: botInfo.userIdBot }
          ]
        }
      });

      if (getSettingValue("whatsaAppCloudApi")?.value == "enabled") {
        if (ticket) {
          await UpdateTicketService({
            ticketData: { status: "closed" },
            ticketId: ticket.id
          });
          ticket = null;
        }
      } else {
        if (ticket) {
          await UpdateTicketService({
            ticketData: { status: "closed" },
            ticketId: ticket.id
          });
        }
      }

      if (!ticket) {
        ticket = await FindOrCreateTicketService(
          contact,
          whatsappId,
          0,
          undefined,
          queueId
        );
        botSendMessage(ticket, msg);
      }

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

      console.log(
        `REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 200 | MSG: success`
      );
      return res.status(200).json({ msg: "success" });
    }

    console.log(
      `REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 500 | MSG: The number ${contact_to} does not exist on WhatsApp`
    );
    return res
      .status(500)
      .json({ msg: `The number ${contact_to} does not exist on WhatsApp` });
  }

  console.log(
    `REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 500 | MSG: Whatsapp number ${contact_from} disconnected or it doesn't exist in omnihit`
  );
  return res.status(500).json({
    msg: `Whatsapp number ${contact_from} disconnected or it doesn't exist in omnihit`
  });
};

export const store = async (req: Request, res: Response): Promise<Response> => {
  const { contactId, status, userId, msg, queueId, whatsappId }: TicketData =
    req.body;

  const botInfo = await BotIsOnQueue("botqueue");

  let ticket = await Ticket.findOne({
    where: {
      [Op.or]: [
        { contactId, status: "queueChoice" },
        { contactId, status: "open", userId: botInfo.userIdBot }
      ]
    }
  });

  if (getSettingValue("whatsaAppCloudApi")?.value == "enabled") {
    if (ticket) {
      await UpdateTicketService({
        ticketData: { status: "closed" },
        ticketId: ticket.id
      });
      ticket = null;
    }
  } else {
    if (ticket) {
      await UpdateTicketService({
        ticketData: { status: "open", userId: userId, queueId },
        ticketId: ticket.id
      });
    }
  }

  if (!ticket) {
    ticket = await CreateTicketService({
      contactId,
      status,
      userId,
      queueId,
      whatsappId
    });
  }

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

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

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

  const contact = await ShowTicketService(ticketId);

  const { statusChatEnd, count, hasMore } = await ListStatusChatEndService({
    searchParam: "",
    pageNumber: "1"
  });

  //////////////////
  const schedulesContact = await ListSchedulingNotifyContactService(
    contact.contact.number
  );
  /////////////////

  return res.status(200).json({ contact, statusChatEnd, schedulesContact });
};

export const count = async (req: Request, res: Response): Promise<Response> => {
  // type indexQ = { status: string; date?: string; };
  const { status, date } = req.query as IndexQuery;

  const ticketCount = await CountTicketService(status, date);

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

export const update = async (
  req: Request,
  res: Response
): Promise<Response> => {
  console.log("ENTROU NO UPDATE TICKET CONTROLLER");

  const { ticketId } = req.params;

  const userOldInfo = await Ticket.findByPk(ticketId);

  let ticket2 = {};

  if (req.body["status"] === "closed") {
    const { status, userId, schedulingNotifyData } = req.body;

    // lembrete
    const scheduleData = JSON.parse(schedulingNotifyData);

    const statusChatEndName = await ShowStatusChatEndService(
      scheduleData.statusChatEndId
    );

    const { ticket } = await UpdateTicketService({
      ticketData: {
        status: status,
        userId: userId,
        statusChatEnd: statusChatEndName.name
      },
      ticketId
    });

    if (scheduleData.farewellMessage) {
      const whatsapp = await ShowWhatsAppService(ticket.whatsappId);

      const { farewellMessage } = whatsapp;

      if (farewellMessage) {
        await SendWhatsAppMessage({ body: farewellMessage, ticket });
      }
    }

    //  lembrete                              // agendamento
    if (
      scheduleData.statusChatEndId === "2" ||
      scheduleData.statusChatEndId === "3"
    ) {
      if (
        isScheduling(scheduleData.schedulingDate, scheduleData.schedulingTime)
      ) {
        console.log("*** É AGENDAMENTO!");
      } else {
        console.log("*** É LEMBRETE!");
      }

      const schedulingNotifyCreate = await CreateSchedulingNotifyService({
        ticketId: scheduleData.ticketId,
        statusChatEndId: scheduleData.statusChatEndId,
        schedulingDate: scheduleData.schedulingDate,
        schedulingTime: scheduleData.schedulingTime,
        message: scheduleData.message
      });
    }

    ticket2 = ticket;
  } else {
    // Para aparecer pendente para todos usuarios que estao na fila
    if (req.body.transfer) {
      req.body.userId = null;
    }

    let ticketData: TicketData = req.body;

    if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
      if (ticketData.transfer) {
        const whatsappsByqueue = await ListWhatsAppsForQueueService(
          ticketData.queueId
        );

        if (userOldInfo) {
          let listTicketOpenPending: any = [];

          for (const w of whatsappsByqueue) {
            let whats = await ListWhatsAppsNumber(w.id);

            console.log("-------> WHATS: ", JSON.stringify(whats, null, 6));
            const ticket = await Ticket.findOne({
              where: {
                [Op.and]: [
                  { contactId: userOldInfo.contactId },
                  {
                    whatsappId: {
                      [Op.in]: whats.whatsapps.map((w: any) => w.id)
                    }
                  },
                  { status: { [Op.or]: ["open", "pending"] } }
                ]
              }
            });

            if (ticket) {
              listTicketOpenPending.push({
                ticketId: ticket.id,
                status: ticket.status,
                userId: ticket.userId,
                contactId: ticket.contactId,
                whatsappId: ticket.whatsappId,
                queueId: ticket.queueId
              });
            }
          }

          // console.log("userOldInfo: ", JSON.stringify(userOldInfo, null, 6));
          // console.log("##########")
          // console.log(
          //   "listTicketOpenPending: ",
          //   JSON.stringify(listTicketOpenPending)
          // );

          if (
            listTicketOpenPending.filter(
              (ob: any) => userOldInfo.whatsappId != ob.whatsappId
            )?.length > 0
          ) {
            throw new AppError("ERR_OTHER_OPEN_TICKET");
          }
        }

        //////////////////////////////////////////////

        // const defaultWhatsapp: any = await GetDefaultWhatsApp({
        //   userId: ticketData.userId
        // });

        // console.log(
        //   "ticketData.userId: ",
        //   ticketData.userId,
        //   " | defaultWhatsapp: ",
        //   JSON.stringify(defaultWhatsapp, null, 6)
        // );

        // const _ticket: any = await Ticket.findByPk(ticketId);

        // if (defaultWhatsapp && ticketData.status != "open") {
        //   await CheckContactOpenTickets(
        //     _ticket.dataValues.contactId,
        //     defaultWhatsapp.dataValues.id
        //   );
        // }

        // ticketData.whatsappId = defaultWhatsapp.dataValues.id;
      }
    }

    console.log(
      "--------> ticketData.status: ",
      ticketData.status,
      " | ticketData.fromMe: ",
      ticketData.fromMe
    );

    const { ticket } = await UpdateTicketService({
      ticketData,
      ticketId
    });

    if (ticketData.status == "open" && !ticketData.fromMe) {
      await setMessageAsRead(ticket);
    }

    if (ticketData.userId) {
      const dateToday = splitDateTime(
        new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
      );
      TicketEmiterSumOpenClosedByUser(
        ticketData.userId.toString(),
        dateToday.fullDate,
        dateToday.fullDate
      );
    }

    ticket2 = ticket;
  }

  if (userOldInfo) {
    const dateToday = splitDateTime(
      new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
    );

    if (userOldInfo.userId) {
      TicketEmiterSumOpenClosedByUser(
        userOldInfo.userId.toString(),
        dateToday.fullDate,
        dateToday.fullDate
      );
    }
  }

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

// export const update = async (
//   req: Request,
//   res: Response
// ): Promise<Response> => {
//   const { ticketId } = req.params;
//   const ticketData: TicketData = req.body;

//   const { ticket } = await UpdateTicketService({
//     ticketData,
//     ticketId
//   });

//   if (ticket.status === "closed") {
//     const whatsapp = await ShowWhatsAppService(ticket.whatsappId);

//     const { farewellMessage } = whatsapp;

//     if (farewellMessage) {
//        await SendWhatsAppMessage({ body: farewellMessage, ticket });
//     }
//   }

//   return res.status(200).json(ticket);
// };

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

  const ticket = await DeleteTicketService(ticketId);

  const io = getIO();
  io.to(ticket.status).to(ticketId).to("notification").emit("ticket", {
    action: "delete",
    ticketId: +ticketId
  });

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