import { defineStore } from 'pinia';
import { ref } from 'vue';
import { Boat, useBoatStore } from './boat';
import { date } from 'quasar';
import { DateOptions } from 'quasar';
import { Timestamp, parseDate } from '@quasar/quasar-ui-qcalendar';

export type StatusTypes = 'tentative' | 'confirmed' | 'pending' | undefined;
export interface Reservation {
  id: number;
  user: string;
  start: Date;
  end: Date;
  resource: Boat;
  reservationDate: Date;
  status?: StatusTypes;
}
// 24 hrs in advance only 2 weekday, and 1 weekend slot
// Within 24 hrs, any available slot
/* TODO: Figure out how best to separate out where qcalendar bits should be.
   e.g.: Should there be any qcalendar stuff in this store?  Or should we have just JS Date
   objects in here? */

export interface Timeblock {
  start: Timestamp;
  end: Timestamp;
  selected?: false;
}

const weekdayBlocks = [
  {
    start: { time: '08:00', hour: 8, minute: 0 },
    end: { time: '12:00', hour: 12, minute: 0 },
  },
  {
    start: { time: '12:00', hour: 12, minute: 0 },
    end: { time: '16:00', hour: 16, minute: 0 },
  },
  {
    start: { time: '17:00', hour: 17, minute: 0 },
    end: { time: '21:00', hour: 21, minute: 0 },
  },
] as Timeblock[];

const weekendBlocks = [
  {
    start: { time: '07:00', hour: 7, minute: 0 },
    end: { time: '10:00', hour: 10, minute: 0 },
  },
  {
    start: { time: '10:00', hour: 10, minute: 0 },
    end: { time: '13:00', hour: 13, minute: 0 },
  },
  {
    start: { time: '13:00', hour: 13, minute: 0 },
    end: { time: '16:00', hour: 16, minute: 0 },
  },
  {
    start: { time: '16:00', hour: 16, minute: 0 },
    end: { time: '19:00', hour: 19, minute: 0 },
  },
];

function getSampleReservations(): Reservation[] {
  const sampleData = [
    {
      id: 1,
      user: 'John Smith',
      start: '12:00',
      end: '15:00',
      boat: '1',
      status: 'confirmed',
    },
    {
      id: 2,
      user: 'Bob Barker',
      start: '18:00',
      end: '21:00',
      boat: '1',
      status: 'confirmed',
    },
    {
      id: 3,
      user: 'Peter Parker',
      start: '9:00',
      end: '12:00',
      boat: '2',
      status: 'tentative',
    },
    {
      id: 4,
      user: 'Vince McMahon',
      start: '15:00',
      end: '18:00',
      boat: '2',
      status: 'pending',
    },
    {
      id: 5,
      user: 'Heather Graham',
      start: '09:00',
      end: '12:00',
      boat: '3',
      status: 'confirmed',
    },
    {
      id: 6,
      user: 'Lawrence Fishburne',
      start: '18:00',
      end: '21:00',
      boat: '3',
    },
  ];
  const boatStore = useBoatStore();
  const now = new Date();
  const splitTime = (x: string): string[] => {
    return x.split(':');
  };
  const makeOpts = (x: string[]): DateOptions => {
    return {
      hour: parseInt(x[0]),
      minute: parseInt(x[1]),
      seconds: 0,
      milliseconds: 0,
    };
  };

  return sampleData.map((entry): Reservation => {
    const boat = <Boat>boatStore.boats.find((b) => b.$id == entry.boat);
    return {
      id: entry.id,
      user: entry.user,
      start: date.adjustDate(now, makeOpts(splitTime(entry.start))),
      end: date.adjustDate(now, makeOpts(splitTime(entry.end))),
      resource: boat,
      reservationDate: now,
      status: entry.status as StatusTypes,
    };
  });
}

export const useScheduleStore = defineStore('schedule', () => {
  // TODO: Implement functions to dynamically pull this data.
  const reservations = ref<Reservation[]>(getSampleReservations());
  const timeblocks = weekdayBlocks;

  const getTimeblocksForDate = (date: Timestamp): Timeblock[] => {
    return timeblocks.map((t) => {
      return {
        // Update all the start/end times with the passed in date
        ...t,
        start: { ...date, ...t.start },
        end: { ...date, ...t.end },
      };
    });
  };

  const getBoatReservations = (
    searchDate: Timestamp,
    boat?: string
  ): Reservation[] => {
    return reservations.value.filter((x) => {
      console.log(searchDate);
      return (
        ((parseDate(x.start)?.date == searchDate.date ||
          parseDate(x.end)?.date == searchDate.date) && // Part of reservation falls on day
          x.resource != undefined && // A boat is defined
          !boat) ||
        x.resource.$id == boat // A specific boat has been passed, and matches
      );
    });
  };

  const getConflictingReservations = (
    resource: Boat,
    start: Date,
    end: Date
  ): Reservation[] => {
    const overlapped = reservations.value.filter(
      (entry: Reservation) =>
        entry.resource.$id == resource.$id &&
        entry.start < end &&
        entry.end > start
    );
    return overlapped;
  };

  const isResourceTimeOverlapped = (
    resource: Boat,
    start: Date,
    end: Date
  ): boolean => {
    return getConflictingReservations(resource, start, end).length > 0;
  };

  const isReservationOverlapped = (res: Reservation): boolean => {
    return isResourceTimeOverlapped(res.resource, res.start, res.end);
  };

  const getNewId = () => {
    // Trivial placeholder
    return Math.max(...reservations.value.map((item) => item.id)) + 1;
  };

  const addOrCreateReservation = (reservation: Reservation) => {
    const index = reservations.value.findIndex(
      (res) => res.id == reservation.id
    );
    index != -1
      ? (reservations.value[index] = reservation)
      : reservations.value.push(reservation);
  };

  return {
    reservations,
    getBoatReservations,
    getConflictingReservations,
    getTimeblocksForDate,
    getNewId,
    addOrCreateReservation,
    isReservationOverlapped,
    isResourceTimeOverlapped,
  };
});
