/**
 * @fileoverview Redux action creators for ComicVine API and comic book information.
 * Provides actions for searching ComicVine, fetching comic metadata, managing
 * library statistics, and applying ComicVine matches to local comic records.
 * @module actions/comicinfo
 */

import axios from "axios";
import rateLimiter from "axios-rate-limit";
import { setupCache } from "axios-cache-interceptor";
import {
  CV_SEARCH_SUCCESS,
  CV_API_CALL_IN_PROGRESS,
  CV_API_GENERIC_FAILURE,
  IMS_COMIC_BOOK_DB_OBJECT_CALL_IN_PROGRESS,
  IMS_COMIC_BOOK_DB_OBJECT_FETCHED,
  CV_ISSUES_METADATA_CALL_IN_PROGRESS,
  CV_CLEANUP,
  IMS_COMIC_BOOKS_DB_OBJECTS_FETCHED,
  CV_ISSUES_MATCHES_IN_LIBRARY_FETCHED,
  CV_ISSUES_FOR_VOLUME_IN_LIBRARY_SUCCESS,
  CV_WEEKLY_PULLLIST_CALL_IN_PROGRESS,
  CV_WEEKLY_PULLLIST_FETCHED,
  LIBRARY_STATISTICS_CALL_IN_PROGRESS,
  LIBRARY_STATISTICS_FETCHED,
} from "../constants/action-types";
import {
  COMICVINE_SERVICE_URI,
  LIBRARY_SERVICE_BASE_URI,
} from "../constants/endpoints";

/**
 * Rate-limited axios instance for ComicVine API calls.
 * Limited to 1 request per second to comply with API rate limits.
 * @constant {AxiosInstance}
 */
const http = rateLimiter(axios.create(), {
  maxRequests: 1,
  perMilliseconds: 1000,
  maxRPS: 1,
});

/**
 * Cached axios instance for reducing redundant API calls.
 * @constant {AxiosInstance}
 */
const cachedAxios = setupCache(axios);

/**
 * Redux thunk action creator to fetch the weekly comic pull list.
 * Retrieves upcoming comic releases from the ComicVine service.
 *
 * @param {Object} options - Query parameters for the pull list request
 * @returns {Function} Redux thunk function that dispatches CV_WEEKLY_PULLLIST_FETCHED
 */
export const getWeeklyPullList = (options) => async (dispatch) => {
  try {
    dispatch({
      type: CV_WEEKLY_PULLLIST_CALL_IN_PROGRESS,
    });
    await cachedAxios(`${COMICVINE_SERVICE_URI}/getWeeklyPullList`, {
      method: "get",
      params: options,
    }).then((response) => {
      dispatch({
        type: CV_WEEKLY_PULLLIST_FETCHED,
        data: response.data.result,
      });
    });
  } catch (error) {
    // Error handling could be added here if needed
  }
};

/**
 * Generic Redux thunk action creator for ComicVine API calls.
 * Handles rate-limited requests to the ComicVine service with configurable
 * endpoints, methods, and parameters.
 *
 * @param {Object} options - API call configuration options
 * @param {string} options.callURIAction - API endpoint action (e.g., "search")
 * @param {string} options.callMethod - HTTP method (GET, POST, etc.)
 * @param {Object} options.callParams - Query parameters for the request
 * @param {any} [options.data] - Request body data
 * @returns {Function} Redux thunk function that dispatches appropriate action based on callURIAction
 */
export const comicinfoAPICall = (options) => async (dispatch) => {
  try {
    dispatch({
      type: CV_API_CALL_IN_PROGRESS,
      inProgress: true,
    });
    const serviceURI = `${COMICVINE_SERVICE_URI}/${options.callURIAction}`;
    const response = await http(serviceURI, {
      method: options.callMethod,
      params: options.callParams,
      data: options.data ? options.data : null,
      headers: {
        "Content-Type": "application/json",
        "Access-Control-Allow-Origin": "*",
      },
    });

    switch (options.callURIAction) {
      case "search":
        dispatch({
          type: CV_SEARCH_SUCCESS,
          searchResults: response.data,
        });
        break;

      default:
        break;
    }
  } catch (error) {
    dispatch({
      type: CV_API_GENERIC_FAILURE,
      error,
    });
  }
};

/**
 * Redux thunk action creator to fetch all issues for a comic series.
 * Retrieves issue list from ComicVine for a given volume/series.
 *
 * @param {string} comicObjectID - ComicVine volume/series ID
 * @returns {Function} Redux thunk function that dispatches CV_ISSUES_FOR_VOLUME_IN_LIBRARY_SUCCESS
 */
export const getIssuesForSeries =
  (comicObjectID: string) => async (dispatch) => {
    dispatch({
      type: CV_ISSUES_METADATA_CALL_IN_PROGRESS,
    });
    dispatch({
      type: CV_CLEANUP,
    });

    const issues = await axios({
      url: `${COMICVINE_SERVICE_URI}/getIssuesForSeries`,
      method: "POST",
      params: {
        comicObjectID,
      },
    });
    dispatch({
      type: CV_ISSUES_FOR_VOLUME_IN_LIBRARY_SUCCESS,
      issues: issues.data.results,
    });
  };

/**
 * Redux thunk action creator to analyze library issues against ComicVine data.
 * Maps issues to query objects and finds matching issues in the local library.
 *
 * @param {Array} issues - Array of ComicVine issue objects to analyze
 * @param {string} issues[].id - Issue ID
 * @param {string} issues[].name - Issue name
 * @param {string} issues[].issue_number - Issue number
 * @param {Object} issues[].volume - Volume information
 * @param {string} issues[].volume.name - Volume name
 * @returns {Function} Redux thunk function that dispatches CV_ISSUES_MATCHES_IN_LIBRARY_FETCHED
 */
export const analyzeLibrary = (issues) => async (dispatch) => {
  dispatch({
    type: CV_ISSUES_METADATA_CALL_IN_PROGRESS,
  });
  const queryObjects = issues.map((issue) => {
    const { id, name, issue_number } = issue;
    return {
      issueId: id,
      issueName: name,
      volumeName: issue.volume.name,
      issueNumber: issue_number,
    };
  });
  const foo = await axios({
    url: `${LIBRARY_SERVICE_BASE_URI}/findIssueForSeries`,
    method: "POST",
    data: {
      queryObjects,
    },
  });
  
  dispatch({
    type: CV_ISSUES_MATCHES_IN_LIBRARY_FETCHED,
    matches: foo.data,
  });
};

/**
 * Redux thunk action creator to fetch library statistics.
 * Retrieves aggregate statistics about the comic library.
 *
 * @returns {Function} Redux thunk function that dispatches LIBRARY_STATISTICS_FETCHED
 */
export const getLibraryStatistics = () => async (dispatch) => {
  dispatch({
    type: LIBRARY_STATISTICS_CALL_IN_PROGRESS,
  });
  const result = await axios({
    url: `${LIBRARY_SERVICE_BASE_URI}/libraryStatistics`,
    method: "GET",
  });

  dispatch({
    type: LIBRARY_STATISTICS_FETCHED,
    data: result.data,
  });
};

/**
 * Redux thunk action creator to fetch detailed comic book information.
 * Retrieves full comic book document from the library database by ID.
 *
 * @param {string} comicBookObjectId - Database ID of the comic book
 * @returns {Function} Redux thunk function that dispatches IMS_COMIC_BOOK_DB_OBJECT_FETCHED
 */
export const getComicBookDetailById =
  (comicBookObjectId: string) => async (dispatch) => {
    dispatch({
      type: IMS_COMIC_BOOK_DB_OBJECT_CALL_IN_PROGRESS,
      IMS_inProgress: true,
    });
    const result = await axios.request({
      url: `${LIBRARY_SERVICE_BASE_URI}/getComicBookById`,
      method: "POST",
      data: {
        id: comicBookObjectId,
      },
    });
    dispatch({
      type: IMS_COMIC_BOOK_DB_OBJECT_FETCHED,
      comicBookDetail: result.data,
      IMS_inProgress: false,
    });
  };

/**
 * Redux thunk action creator to fetch multiple comic books by their IDs.
 * Retrieves full comic book documents from the library database for a list of IDs.
 *
 * @param {Array<string>} comicBookObjectIds - Array of database IDs
 * @returns {Function} Redux thunk function that dispatches IMS_COMIC_BOOKS_DB_OBJECTS_FETCHED
 */
export const getComicBooksDetailsByIds =
  (comicBookObjectIds: Array<string>) => async (dispatch) => {
    dispatch({
      type: IMS_COMIC_BOOK_DB_OBJECT_CALL_IN_PROGRESS,
      IMS_inProgress: true,
    });
    const result = await axios.request({
      url: `${LIBRARY_SERVICE_BASE_URI}/getComicBooksByIds`,
      method: "POST",
      data: {
        ids: comicBookObjectIds,
      },
    });
    dispatch({
      type: IMS_COMIC_BOOKS_DB_OBJECTS_FETCHED,
      comicBooks: result.data,
    });
  };

/**
 * Redux thunk action creator to apply ComicVine metadata to a local comic.
 * Associates a ComicVine match with a comic book record in the database,
 * updating the comic with metadata from ComicVine.
 *
 * @param {Object} match - ComicVine match object containing metadata to apply
 * @param {string} comicObjectId - Database ID of the local comic book to update
 * @returns {Function} Redux thunk function that dispatches IMS_COMIC_BOOK_DB_OBJECT_FETCHED
 */
export const applyComicVineMatch =
  (match, comicObjectId) => async (dispatch) => {
    dispatch({
      type: IMS_COMIC_BOOK_DB_OBJECT_CALL_IN_PROGRESS,
      IMS_inProgress: true,
    });
    const result = await axios.request({
      url: `${LIBRARY_SERVICE_BASE_URI}/applyComicVineMetadata`,
      method: "POST",
      data: {
        match,
        comicObjectId,
      },
    });
    dispatch({
      type: IMS_COMIC_BOOK_DB_OBJECT_FETCHED,
      comicBookDetail: result.data,
      IMS_inProgress: false,
    });
  };
