import { api } from '@flaschengeist/api';
import { AxiosError } from 'axios';
import { defineStore } from 'pinia';

interface UserService {
  user: FG.Service;
}

function fixJob(job: FG.Job) {
  job.start = new Date(job.start);
  if (job.end) job.end = new Date(job.end);
}

function fixEvent(event: FG.Event) {
  event.start = new Date(event.start);
  if (event.end) event.end = new Date(event.end);

  event.jobs.forEach((job) => fixJob(job));
}

export const useScheduleStore = defineStore({
  id: 'schedule',

  state: () => ({
    jobTypes: [] as FG.JobType[],
    eventTypes: [] as FG.EventType[],
    templates: [] as FG.Event[],
  }),

  getters: {},

  actions: {
    async getJobTypes(force = false) {
      if (force || this.jobTypes.length == 0)
        try {
          const { data } = await api.get<FG.JobType[]>('/events/job-types');
          this.jobTypes = data;
        } catch (error) {
          throw error;
        }
      return this.jobTypes;
    },

    async addJobType(name: string) {
      try {
        const { data } = await api.post<FG.JobType>('/events/job-types', { name: name });
        this.jobTypes.push(data);
      } catch (error) {
        // TODO: HANDLE ERROR
        throw error;
      }
    },

    async removeJobType(id: number) {
      await api.delete(`/events/job-types/${id}`);
      //Todo Handle delete JT
    },

    async renameJobType(id: number, newName: string) {
      await api.put(`/events/job-types/${id}`, { name: newName });
      // TODO handle rename
    },

    async getEventTypes(force = false) {
      if (force || this.eventTypes.length == 0)
        try {
          const { data } = await api.get<FG.EventType[]>('/events/event-types');
          this.eventTypes = data;
        } catch (error) {
          throw error;
        }
      return this.eventTypes;
    },

    /** Add new EventType
     *
     * @param name Name of new EventType
     * @returns EventType object or null if name already exists
     * @throws Exception if requests fails because of an other reason
     */
    async addEventType(name: string) {
      try {
        const { data } = await api.post<FG.EventType>('/events/event-types', { name: name });
        return data;
      } catch (error) {
        if ('response' in error) {
          const ae = <AxiosError>error;
          if (ae.response && ae.response.status == 409 /* CONFLICT */) return null;
        }
        throw error;
      }
    },
    async removeEvent(id: number) {
      try {
        await api.delete(`/events/${id}`);
        const idx = this.templates.findIndex((v) => v.id === id);
        if (idx !== -1) this.templates.splice(idx, 1);
      } catch (e) {
        const error = <AxiosError>e;
        if (error.response && error.response.status === 404) return false;
        throw e;
      }
      return true;
    },

    async removeEventType(id: number) {
      await api.delete(`/events/event-types/${id}`);
      // TODO handle delete
    },

    async renameEventType(id: number, newName: string) {
      try {
        await api.put(`/events/event-types/${id}`, { name: newName });
        // TODO handle rename
        return true;
      } catch (error) {
        if ('response' in error) {
          const ae = <AxiosError>error;
          if (ae.response && ae.response.status == 409 /* CONFLICT */) return false;
        }
        throw error;
      }
    },

    async getTemplates(force = false) {
      if (force || this.templates.length == 0) {
        const { data } = await api.get<FG.Event[]>('/events/templates');
        data.forEach((element) => fixEvent(element));
        this.templates = data;
      }
      return this.templates;
    },

    async getEvents(filter: { from?: Date; to?: Date } | undefined = undefined) {
      try {
        const { data } = await api.get<FG.Event[]>('/events', { params: filter });
        data.forEach((element) => fixEvent(element));
        return data;
      } catch (error) {
        throw error;
      }
    },

    async getEvent(id: number) {
      try {
        const { data } = await api.get<FG.Event>(`/events/${id}`);
        fixEvent(data);
        return data;
      } catch (error) {
        throw error;
      }
    },

    async updateJob(eventId: number, jobId: number, service: FG.Service | UserService) {
      try {
        const { data } = await api.put<FG.Job>(`/events/${eventId}/jobs/${jobId}`, service);
        fixJob(data);
        return data;
      } catch (error) {
        throw error;
      }
    },

    async addEvent(event: FG.Event) {
      const { data } = await api.post<FG.Event>('/events', event);
      if (data.is_template) this.templates.push(data);
      return data;
    },
  },
});