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, where } 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";
import { del, get, set } from "../helpers/RedisClient";
import CountStatusChatEndService from "../services/StatusChatEndService/CountStatusChatEndService";
import Queue from "../models/Queue";
import StatusChatEnd from "../models/StatusChatEnd";
import controllByNumber from "../helpers/controllByNumber";

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, remoteTicketsControll } =
    await ListTicketsService({
      searchParam,
      pageNumber,
      status,
      date,
      showAll,
      userId,
      queueIds,
      withUnreadMessages,
      unlimited,
      searchParamContent
    });

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

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

  let whatsappId: any;

  if (!queueId && !contact_from && !cc) {
    return res.status(400).json({
      error: `Property 'queueId' or 'contact_from' or 'cc' is required.`
    });
  }

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

  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` });
      }
    }
  }

  if (queueId) {
    const whatsapps = await ListWhatsAppsForQueueService(queueId, "CONNECTED");

    if (!whatsapps || whatsapps?.length == 0) {
      return res.status(500).json({
        msg: `queueId ${queueId} does not have a WhatsApp number associated with it or the number's session is disconnected.`
      });
    }

    const { id } = whatsapps[0];

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

    if (!whatsapp) {
      return res.status(404).json({
        msg: `Whatsapp number ${contact_from} not found or disconnected!`
      });
    }

    const { id } = whatsapp;

    const { queues } = await ShowWhatsAppService(id);

    if (!queues || queues.length == 0) {
      return res.status(500).json({
        msg: `The WhatsApp number ${contact_from} is not associated with any queue! `
      });
    }

    queueId = queues[0].id;
    whatsappId = id;
  } else if (cc) {
    const queue = await Queue.findOne({ where: { cc } });
    if (!queue) {
      return res.status(404).json({
        msg: `Queue with cc ${cc} not found! `
      });
    }

    queueId = queue.id;

    const whatsapps = await ListWhatsAppsForQueueService(queueId, "CONNECTED");

    if (whatsapps.length === 0) {
      return res.status(500).json({
        msg: `No WhatsApp found for this cc ${cc} or the WhatsApp number is disconnected! `
      });
    }

    whatsappId = whatsapps[0].id;
  }

  // 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");

    // ticket from queueChoice or bot
    let ticket: any = 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
        });
      }
    }

    ticket = await Ticket.findOne({
      where: {
        [Op.or]: [
          { contactId, status: "pending" },
          { contactId, status: "open" }
        ]
      }
    });

    if (ticket) {
      console.log(
        `THE CAMPAIGN TICKET WAS NOT CREATED BECAUSE THE TICKET IS PENDING OR OPEN`
      );

      return res.status(422).json({
        msg: `The campaign ticket was not created because the number ${contact_to} already has a ticket open or pending`
      });
    }

    ticket = await FindOrCreateTicketService(
      contact,
      whatsappId,
      0,
      undefined,
      queueId,
      true
    );

    // botSendMessage(ticket, `${msg}`);

    await ticket.update({
      lastMessage: msg
    });

    await set(
      `remote:ticketId:${ticket.id}`,
      JSON.stringify({
        id: ticket.id,
        createdAt: ticket.createdAt,
        updatedAt: ticket.updatedAt,
        whatsappId: ticket.whatsappId,
        status: ticket.status
      })
    );

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

    const obj = await controllByNumber();

    if (obj?.tickets) {
      io.emit("remoteTickesControll", {
        action: "update",
        tickets: obj.ticketIds
      });
    }

    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` });
};

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, queueIds } = req.query as IndexQuery;
  const ticketCount = await CountTicketService(status, date, queueIds);

  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);

    console.log("scheduleData: ", scheduleData);

    const statusChatEnd = await ShowStatusChatEndService({
      name: scheduleData.statusChatEndName
    });

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

    let _farewellMessage;

    if (getSettingValue("farewellMessageByStatusChatEnd")?.value == "enabled") {
      const statusChatEndData = await get({
        key: `statusChatEnd:${statusChatEnd.id}`,
        parse: true
      });

      if (
        statusChatEndData &&
        statusChatEndData?.farewellMessage &&
        statusChatEndData?.farewellMessage?.trim()?.length > 0
      ) {
        const { farewellMessage } = statusChatEndData;

        _farewellMessage = farewellMessage;
      }
    } else if (getSettingValue("farewellMessageByQueue")?.value == "enabled") {
      const queueData = await get({
        key: `queue:${ticket.queueId}`,
        parse: true
      });

      if (
        queueData &&
        queueData?.farewellMessage &&
        queueData?.farewellMessage?.trim()?.length > 0
      ) {
        const { farewellMessage } = queueData;

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

      const { farewellMessage } = whatsapp;

      if (farewellMessage) {
        _farewellMessage = farewellMessage;
      }
    }

    if (_farewellMessage) {
      await SendWhatsAppMessage({ body: `\u200e${_farewellMessage}`, ticket });
    }

    console.log("tatusChatEnd.name: ", statusChatEnd.name);

    if (
      statusChatEnd.name === "LEMBRETE" ||
      statusChatEnd.name === "AGENDAMENTO À CONFIRMAR"
    ) {
      //  lembrete                              // agendamento
      if (
        isScheduling(scheduleData.schedulingDate, scheduleData.schedulingTime)
      ) {
        console.log("*** É AGENDAMENTO!");
      } else {
        console.log("*** É LEMBRETE!");
      }

      const schedulingNotifyCreate = await CreateSchedulingNotifyService({
        ticketId: scheduleData.ticketId,
        statusChatEndId: `${statusChatEnd.id}`,
        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);

            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.status == "open" || ticketData.status == "pending") {
      let ticketRemote = await get({
        key: `remote:ticketId:${ticketId}`
      });

      if (ticketRemote) {
        ticketRemote = JSON.parse(ticketRemote);

        ticketRemote = {
          ...ticketRemote,
          ...{
            status: ticketData.status == "open" ? "open" : "pending",
            updatedAt: ticket.updatedAt
          }
        };

        set(`remote:ticketId:${ticketId}`, JSON.stringify(ticketRemote));
      }
    }

    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
  });

  await del(`remote:ticketId:${ticketId}`);

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