import { useMutation, useQuery } from "@tanstack/react-query";
import axios from "axios";
import { STATUSES } from "./config";
import { useMode } from "./stores/useMode.js";
import { RANGE_FILTERS_KEYS, usePendingPointsFilters } from "./stores/usePendingPointsFilters";
import { usePointSelection } from "./stores/usePointSelection";
import { useUpdateLayerCounter } from "./stores/useUpdateLayerCounter.js";
import { appendFiltersInUse } from "./utils.js";

export const BASE_URL = import.meta.env.VITE_API_URL;

export const api = axios.create({
  baseURL:
    import.meta.env.MODE === "development"
      ? "http://localhost:5173/"
      : BASE_URL,
});

export const useDbTableName = () => {
  const { isImportMode } = useMode();
  if (isImportMode) return "pre_placement_points";
  return "placement_points";
}

export const useSourceLayerName = () => {
  const { isImportMode } = useMode();
  if (isImportMode) return "public.prepoints_with_dist";
  return "public.points_with_dist";
}

const enrichParamsWithRegionFilter = (params, region) => {
  const resultParams = params ? params : new URLSearchParams();

  if (region) {
    if (region.type === "ao") {
      resultParams.append("district[]", region.id);
    }

    if (region.type === "rayon") {
      resultParams.append("area[]", region.id);
    }
  }

  return resultParams;
};

export const getPoints = async (params, region, dbTable = "placement_points", signal) => {
  const resultParams = enrichParamsWithRegionFilter(params, region);

  const { data } = await api.get(
    `https://postamates.spatialsystems.ru/api/${dbTable}/?${resultParams.toString()}`, { signal }
  );

  return data;
};

export const exportPoints = async (params, region, dbTable = "placement_points") => {
  const resultParams = enrichParamsWithRegionFilter(params, region);

  const { data } = await api.get(
    `https://postamates.spatialsystems.ru/api/${dbTable}/to_excel/?${resultParams.toString()}`,
    { responseType: "arraybuffer" }
  );

  return data;
};

export const downloadImportTemplate = async () => {
  const { data } = await api.get(
    'https://postamates.spatialsystems.ru/api/pre_placement_points/download_template/',
    { responseType: "arraybuffer" }
  );

  return data;
};

export const uploadPointsFile = async (file, config) => {
  const formData = new FormData();
  formData.append("file", file);
  const { data } = await api.post(
    `https://postamates.spatialsystems.ru/api/pre_placement_points/load_matching_file/`,
    formData,
    config
  );

  return data;
};

export const importPoints = async (id) => {
  const formData = new FormData();
  formData.append("id", id);
  const { data } = await api.post(
    `https://postamates.spatialsystems.ru/api/pre_placement_points/start_matching/`,
    formData
  );

  return data;
};

export const getImportStatus = async () => {
  const { data } = await api.get(
    `https://postamates.spatialsystems.ru/api/pre_placement_points/import_status/`
  );

  return data;
};

export const useGetTotalInitialPointsCount = () => {
  const dbTable = useDbTableName();
  const { updateCounter } = useUpdateLayerCounter();
  return useQuery(
    ["all-initial-count", dbTable, updateCounter],
    async ({ signal }) => {
      const params = new URLSearchParams({
        page: 1,
        page_size: 1,
      });
      params.append("status[]", [STATUSES.pending, STATUSES.cancelled]);

      return await getPoints(params, null, dbTable, signal);
    },
    {
      select: (data) => data.count,
      refetchOnWindowFocus: false
    }
  );
};

export const useGetFilteredPendingPointsCount = (isMerge) => {
  const { filters, ranges } = usePendingPointsFilters();
  const { updateCounter } = useUpdateLayerCounter();
  const {
    categories,
    region,
  } = filters;
  const {
    selection: { included },
  } = usePointSelection();

  const includedIds = [...included];
  const getParams = () => {
    const params = new URLSearchParams({
      page: 1,
      page_size: 1,
      "categories[]": categories,
      "included[]": includedIds,
    });
    params.append("status[]", STATUSES.pending);

    appendFiltersInUse(params, filters, ranges);

    return params;
  }

  const getMergeParams = () => {
    return new URLSearchParams({
      "matching_status": "New",
    });
  }

  const dbTable = useDbTableName();

  return useQuery(
    ["filtered-points", filters, dbTable, includedIds, updateCounter],
    async ({ signal }) => {
      const params = isMerge ? getMergeParams() : getParams();

      return await getPoints(params, region, dbTable, signal);
    },
    {
      select: (data) => data.count,
      keepPreviousData: true,
      refetchOnWindowFocus: false
    }
  );
};

export const useGetPointsToMergeCount = () => {
  const getMergeParams = () => {
    return new URLSearchParams({
      "matching_status": "New",
    });
  }

  const dbTable = useDbTableName();

  return useQuery(
    ["filtered-points", dbTable],
    async () => {
      const params = getMergeParams();

      return await getPoints(params, null, dbTable);
    },
    { select: (data) => data.count, keepPreviousData: true }
  );
};

export const useMergePointsToDb = () => {
  return useMutation({
    mutationFn: () => {
      return api.post(
        `https://postamates.spatialsystems.ru/api/pre_placement_points/move_points/`
      );
    },
  });
};

export const useGetPermissions = () => {
  return "editor"
  // const { setImportMode } = useMode();
  // return useQuery(["permissions"], async () => {
  //   const { data } = await api.get("https://postamates.spatialsystems.ru/api/me/");

  //   if (data?.groups?.includes("postnet_editor")) {
  //     return "editor";
  //   }

  //   setImportMode(false);
  //   return "viewer";
  // });
};

const TASK_STATUSES = {
  finished: "Перерасчет ML завершен"
}

export const useUpdatePostamatId = () => {
  return useMutation({
    mutationFn: (params) => {
      return api.put(
        `https://postamates.spatialsystems.ru/api/placement_points/update_postamat_id/?${params.toString()}`
      );
    },
  });
};

export const getLastMLRun = async () => {
  const { data } = await api.get(
    `https://postamates.spatialsystems.ru/api/placement_points/last_time_ml_run/`
  );

  return data;
};

export const startML = async () => {
  const { data } = await api.get(
    `https://postamates.spatialsystems.ru/api/placement_points/start/`
  );

  return data;
};

export const getPostamatesAndPvzGroups = async () => {
  const { data } = await api.get(
    `https://postamates.spatialsystems.ru/api/postamate_and_pvz_groups/`
  );

  return data;
};

export const usePostamatesAndPvzGroups = () => {
  return useQuery(
    ['groups'],
    async () => {
      return await getPostamatesAndPvzGroups();
    },
  );
};

export const getOtherGroups = async () => {
  const { data } = await api.get(
    `https://postamates.spatialsystems.ru/api/other_object_groups/`
  );

  return data;
};

export const useOtherGroups = () => {
  return useQuery(
    ['other_groups'],
    async () => {
      return await getOtherGroups();
    },
  );
};

export const useLastMLRun = () => {
  return useQuery(
    ['last_time'],
    async () => {
      return await getLastMLRun();
    },
    {
      refetchInterval: 5000,
    }
  );
}

export const useGetPendingPointsRange = (dbTable) => {
  const { isImportMode } = useMode();
  const statusFilter = isImportMode ? '' : `?status[]=${STATUSES.pending}`;

  return useQuery(
    ["prediction-max-min", dbTable],
    async () => {
      const { data, isInitialLoading, isFetching } = await api.get(
        `https://postamates.spatialsystems.ru/api/${dbTable}/filters/${statusFilter}`
      );
      return { data, isLoading: isInitialLoading || isFetching };
    },
    {
      select: ({ data, isLoading }) => {
        const distToGroupsArr = data.dist_to_groups.map((groupRange) => {
          return {
            [`d${groupRange.group_id}`]: [Math.floor(groupRange.dist[0]), Math.min(Math.ceil(groupRange.dist[1]), 4000)],
          }
        });
        const distToGroups = Object.assign({}, ...distToGroupsArr);
        const rangesArr = RANGE_FILTERS_KEYS.map((key) => {
          if ((/d[0-9]/.test(key))) return;
          return {
            [key]: [Math.floor(data[key][0]), Math.ceil(data[key][1])]
          }
        }).filter(item => !!item);
        const ranges = Object.assign({}, ...rangesArr);
        return {
          fullRange: {
            prediction: data.prediction_current,
            ...ranges,
            ...distToGroups
          },
          isLoading: isLoading
        };
      },
    }
  );
};

export const useGetPopupPoints = (features) => {
  const pointsIds = features.map(f => f.properties.id);
  const dbTable = useDbTableName();

  const { data, isInitialLoading, isFetching } = useQuery(
    ["popup_data", features],
    async () => {
      const params = new URLSearchParams({
        "location_ids[]": pointsIds,
      });

      const { data } = await api.get(
        `https://postamates.spatialsystems.ru/api/${dbTable}/?${params.toString()}`
      );

      return data.results;
    },
    {
      refetchOnWindowFocus: false,
      refetchOnMount: false
    }
  );

  return { data, isLoading: isInitialLoading || isFetching };
};

export const deletePoint = async (id) => {
  const formData = new FormData();
  formData.append("ids", id);
  await api.delete(
    `https://postamates.spatialsystems.ru/api/pre_placement_points/delete_points/`,
    { data: formData }
  )
}
