import SettingTicket from "../models/SettingTicket";
import { splitDateTime } from "./SplitDateTime";
import { utcToZonedTime, zonedTimeToUtc } from "date-fns-tz";

import {
  format as _format,
  isWithinInterval,
  parse,
  subMinutes,
  isSaturday,
  isSunday,
  parseISO
} from "date-fns";
import ptBR from "date-fns/locale/pt-BR";

const isHoliday = async (number: string | number) => {
  let obj = { set: false, msg: "" };

  const holiday = await SettingTicket.findOne({
    where: { key: "holiday", number }
  });

  if (
    holiday &&
    holiday.value == "enabled" &&
    holiday.message?.trim()?.length > 0
  ) {
    const startTime = splitDateTime(
      new Date(
        _format(new Date(holiday.startTime), "yyyy-MM-dd HH:mm:ss", {
          locale: ptBR
        })
      )
    );

    const currentDate = splitDateTime(
      new Date(
        _format(new Date(), "yyyy-MM-dd HH:mm:ss", {
          locale: ptBR
        })
      )
    );

    if (currentDate.fullDate == startTime.fullDate) {
      obj.set = true;
      obj.msg = holiday.message.trim();
    }
  }

  return obj;
};

const isWeekend = async (number: string | number) => {
  let obj = { set: false, msg: "" };

  const weekend = await SettingTicket.findOne({
    where: { key: "weekend", number }
  });

  if (
    weekend &&
    weekend.value == "enabled" &&
    weekend.message?.trim()?.length > 0
  ) {
    // Convert parsed date to Brazil time zone
    const localDate = localDateConvert();

    // Check if it's Saturday or Sunday
    if (isSaturday(localDate)) {
      const saturday = await SettingTicket.findOne({
        where: { key: "saturday" }
      });

      if (saturday && saturday.value == "enabled") {
        //  botSendMessage(ticket, weekend.message);
        obj.set = true;
        obj.msg = weekend.message;
      }
    } else if (isSunday(localDate)) {
      const sunday = await SettingTicket.findOne({
        where: { key: "sunday" }
      });

      if (sunday && sunday.value == "enabled") {
        //  botSendMessage(ticket, weekend.message);
        obj.set = true;
        obj.msg = weekend.message;
      }
    } else {
      //  obj.set = true;
      //  obj.msg = weekend.message;
    }
    return obj;
  }
};

async function isOutBusinessTime(number: string | number) {
  let obj = { set: false, msg: "" };

  const outBusinessHours = await SettingTicket.findOne({
    where: { key: "outBusinessHours", number }
  });

  let isWithinRange = false;

  if (
    outBusinessHours &&
    outBusinessHours.value == "enabled" &&
    outBusinessHours?.message?.trim()?.length > 0
  ) {
    const ticketDateTimeUpdate = splitDateTime(
      new Date(
        _format(new Date(), "yyyy-MM-dd HH:mm:ss", {
          locale: ptBR
        })
      )
    );

    const startTime = splitDateTime(
      new Date(
        _format(new Date(outBusinessHours.startTime), "yyyy-MM-dd HH:mm:ss", {
          locale: ptBR
        })
      )
    );

    const endTime = splitDateTime(
      new Date(
        _format(new Date(outBusinessHours.endTime), "yyyy-MM-dd HH:mm:ss", {
          locale: ptBR
        })
      )
    );

    const format = "HH:mm:ss";
    const parsedStartTime = parse(
      ticketDateTimeUpdate.fullTime,
      format,
      new Date()
    );
    const parsedEndTime = parse(startTime.fullTime, format, new Date());
    const parsedTimeToCheck = parse(endTime.fullTime, format, new Date());
    const timeInterval = { start: parsedStartTime, end: parsedEndTime };

    // If the time range spans across different days, handle the date part
    if (parsedEndTime < parsedStartTime) {
      const nextDay = new Date(parsedStartTime);
      nextDay.setDate(nextDay.getDate() + 1);
      timeInterval.end = nextDay;
    }

    isWithinRange = isWithinInterval(parsedTimeToCheck, timeInterval);

    if (!isWithinRange) {
      obj.set = true;
      obj.msg = outBusinessHours.message;
    }
  }

  return obj;
}

async function isOutBusinessTimeSaturday(number: string | number) {
  let obj = { set: false, msg: "" };

  // Convert parsed date to Brazil time zone
  const localDate = localDateConvert();

  // Check if it's Saturday or Sunday
  if (!isSaturday(localDate)) {
    return obj;
  }

  const outBusinessHoursSaturday = await SettingTicket.findOne({
    where: { key: "saturdayBusinessTime", number }
  });

  let isWithinRange = false;

  if (
    outBusinessHoursSaturday &&
    outBusinessHoursSaturday.value == "enabled" &&
    outBusinessHoursSaturday?.message?.trim()?.length > 0
  ) {
    const ticketDateTimeUpdate = splitDateTime(
      new Date(
        _format(new Date(), "yyyy-MM-dd HH:mm:ss", {
          locale: ptBR
        })
      )
    );

    const startTime = splitDateTime(
      new Date(
        _format(
          new Date(outBusinessHoursSaturday.startTime),
          "yyyy-MM-dd HH:mm:ss",
          {
            locale: ptBR
          }
        )
      )
    );

    const endTime = splitDateTime(
      new Date(
        _format(
          new Date(outBusinessHoursSaturday.endTime),
          "yyyy-MM-dd HH:mm:ss",
          {
            locale: ptBR
          }
        )
      )
    );

    const format = "HH:mm:ss";
    const parsedStartTime = parse(
      ticketDateTimeUpdate.fullTime,
      format,
      new Date()
    );
    const parsedEndTime = parse(startTime.fullTime, format, new Date());
    const parsedTimeToCheck = parse(endTime.fullTime, format, new Date());
    const timeInterval = { start: parsedStartTime, end: parsedEndTime };

    // If the time range spans across different days, handle the date part
    if (parsedEndTime < parsedStartTime) {
      const nextDay = new Date(parsedStartTime);
      nextDay.setDate(nextDay.getDate() + 1);
      timeInterval.end = nextDay;
    }

    isWithinRange = isWithinInterval(parsedTimeToCheck, timeInterval);

    if (!isWithinRange) {
      obj.set = true;
      obj.msg = outBusinessHoursSaturday.message;
    }
  }

  return obj;
}

function localDateConvert() {
  const brazilTimeZone = "America/Sao_Paulo";

  const currentDateUtc = new Date();

  // Convert UTC date to Brazil time zone
  const currentDate = utcToZonedTime(currentDateUtc, brazilTimeZone);

  // Format the date using the desired format
  const formattedDate = _format(currentDate, "yyyy-MM-dd HH:mm:ssXXX");

  const parsedDate = parseISO(formattedDate);

  // Convert parsed date to Brazil time zone
  const localDate = utcToZonedTime(parsedDate, brazilTimeZone);
  return localDate;
}

export { isWeekend, isHoliday, isOutBusinessTime, isOutBusinessTimeSaturday };
