import { AxiosError } from 'axios';
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
import {
  AttachmentData,
  AttachmentResponse,
  AttachmentsListResponse,
  CreateAttachmentRequest,
  GetAttachmentsParams,
} from '@/utils/types/attachments.types';

export interface AttachmentsState {
  loading: boolean;
  error: string | null;
  data: AttachmentsListResponse | null;
  singleAttachment: AttachmentData | null;
  uploadLoading: boolean;
  uploadError: string | null;
  uploadResponse: AttachmentData | null;
  deleteLoading: boolean;
  deleteError: string | null;
  deleteSuccess: boolean;

  // Actions
  getAttachments: (
    params: GetAttachmentsParams,
    apiGet: (url: string) => Promise<AttachmentsListResponse>
  ) => Promise<void>;
  getAttachment: (
    id: number,
    apiGet: (url: string) => Promise<AttachmentResponse>
  ) => Promise<void>;
  uploadAttachment: (
    formData: FormData,
    apiPost: (url: string, data: FormData) => Promise<AttachmentResponse>
  ) => Promise<void>;
  deleteAttachment: (
    id: number,
    apiDelete: (url: string) => Promise<void>
  ) => Promise<void>;
  downloadAttachment: (
    id: number,
    apiGet: (url: string) => Promise<Blob>
  ) => Promise<void>;
  clearError: () => void;
  clearUploadError: () => void;
  clearDeleteError: () => void;
  reset: () => void;
}

export interface AttachmentsActions {
  getAttachments: (params: GetAttachmentsParams) => Promise<void>;
  getAttachment: (id: number) => Promise<void>;
  uploadAttachment: (data: CreateAttachmentRequest) => Promise<void>;
  deleteAttachment: (id: number) => Promise<void>;
  downloadAttachment: (id: number) => Promise<void>;
  clearError: () => void;
  clearUploadError: () => void;
  clearDeleteError: () => void;
  reset: () => void;
}

export type AttachmentsStore = AttachmentsState & AttachmentsActions;

const initialState = {
  data: null,
  singleAttachment: null,
  loading: false,
  error: null,
  uploadLoading: false,
  uploadError: null,
  uploadResponse: null,
  deleteLoading: false,
  deleteError: null,
  deleteSuccess: false,
};
const API_PATHS = {
  attachments: {
    list: '/api/attachments',
    delete: (id: number) => `/api/attachments/${id}`,
    download: (id: number) => `/api/attachments/${id}/download`,
  },
  customer: {
    getAllAttachments: (queryParams: string) =>
      `/api/customer/attachments?${queryParams}`,
    getAttachment: (id: number) => `/api/customer/attachments/${id}`,
  },
};
export const useAttachmentsStore = create<AttachmentsStore>()(
  devtools(
    set => ({
      ...initialState,

      getAttachments: async (
        params: GetAttachmentsParams,
        apiGet: (url: string) => Promise<AttachmentsListResponse>
      ) => {
        set({ loading: true, error: null }, false, 'getAttachments/pending');

        try {
          const queryParams = new URLSearchParams();
          Object.entries(params).forEach(([key, value]) => {
            if (value !== undefined && value !== null) {
              queryParams.append(key, String(value));
            }
          });

          const url = API_PATHS.customer.getAllAttachments(queryParams.toString());
          const data = await apiGet(url);
          set({ data, loading: false }, false, 'getAttachments/fulfilled');
        } catch (err) {
          const error = err as AxiosError<{ message?: string }>;
          const message = error.message || 'Unknown error occurred';
          set(
            { error: message, loading: false },
            false,
            'getAttachments/rejected'
          );
        }
      },

      getAttachment: async (
        id: number,
        apiGet: (url: string) => Promise<AttachmentResponse>
      ) => {
        set({ loading: true, error: null }, false, 'getAttachment/pending');

        try {
          const url = API_PATHS.customer.getAttachment(id);
          const response = await apiGet(url);
          set(
            { singleAttachment: response.data, loading: false },
            false,
            'getAttachment/fulfilled'
          );
        } catch (err) {
          const error = err as AxiosError<{ message?: string }>;
          const message = error.message || 'Unknown error occurred';
          set(
            { error: message, loading: false },
            false,
            'getAttachment/rejected'
          );
        }
      },

      uploadAttachment: async (
        formData: FormData,
        apiPost: (url: string, data: FormData) => Promise<AttachmentResponse>
      ) => {
        set(
          { uploadLoading: true, uploadError: null },
          false,
          'uploadAttachment/pending'
        );

        try {
          const url = API_PATHS.attachments.list;
          const response = await apiPost(url, formData);
          set(
            {
              uploadResponse: response.data,
              uploadLoading: false,
            },
            false,
            'uploadAttachment/fulfilled'
          );
        } catch (err) {
          const error = err as AxiosError<{ message?: string }>;
          const message = error.message || 'Unknown error occurred';
          set(
            { uploadError: message, uploadLoading: false },
            false,
            'uploadAttachment/rejected'
          );
        }
      },

      deleteAttachment: async (
        id: number,
        apiDelete: (url: string) => Promise<void>
      ) => {
        set(
          { deleteLoading: true, deleteError: null, deleteSuccess: false },
          false,
          'deleteAttachment/pending'
        );

        try {
          const url = API_PATHS.attachments.delete(id);
          await apiDelete(url);
          set(
            { deleteLoading: false, deleteSuccess: true },
            false,
            'deleteAttachment/fulfilled'
          );
        } catch (err) {
          const error = err as AxiosError<{ message?: string }>;
          const message = error.message || 'Unknown error occurred';
          set(
            { deleteError: message, deleteLoading: false },
            false,
            'deleteAttachment/rejected'
          );
        }
      },

      downloadAttachment: async (
        id: number,
        apiGet: (url: string) => Promise<Blob>
      ) => {
        try {
          const url = API_PATHS.attachments.download(id);
          const blob = await apiGet(url);

          // Create download link
          const downloadUrl = window.URL.createObjectURL(blob);
          const link = document.createElement('a');
          link.href = downloadUrl;
          link.download = `attachment-${id}`;
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);
          window.URL.revokeObjectURL(downloadUrl);
        } catch (err) {
          const error = err as AxiosError<{ message?: string }>;
          const message = error.message || 'Download failed';
          set({ error: message }, false, 'downloadAttachment/rejected');
        }
      },

      clearError: () => set({ error: null }, false, 'clearError'),
      clearUploadError: () => set({ uploadError: null }, false, 'clearUploadError'),
      clearDeleteError: () => set({ deleteError: null, deleteSuccess: false }, false, 'clearDeleteError'),
      reset: () => set(initialState, false, 'reset'),
    }),
    {
      name: 'attachments-store',
    }
  )
);

// Selector functions for optimized subscriptions
export const attachmentsSelector = {
  // Data selectors
  getData: () => useAttachmentsStore.getState().data,
  getSingleAttachment: () => useAttachmentsStore.getState().singleAttachment,
  getUploadResponse: () => useAttachmentsStore.getState().uploadResponse,

  // Loading selectors
  getLoading: () => useAttachmentsStore.getState().loading,
  getUploadLoading: () => useAttachmentsStore.getState().uploadLoading,
  getDeleteLoading: () => useAttachmentsStore.getState().deleteLoading,

  // Error selectors
  getError: () => useAttachmentsStore.getState().error,
  getUploadError: () => useAttachmentsStore.getState().uploadError,
  getDeleteError: () => useAttachmentsStore.getState().deleteError,
  getDeleteSuccess: () => useAttachmentsStore.getState().deleteSuccess,
};

export default useAttachmentsStore; 