import { fetchUNMastersType, fetchUNMastersTypes } from '@api/ranking';
import { StoreType, storage } from 'src/storage';

const NAMESPACE = 'UNMasters';

function saveData<T>(key: string, data: T) {
  const namespacedKey = `${NAMESPACE}:${key}`;
  const jsonData = JSON.stringify(data);
  storage.set(namespacedKey, jsonData);
}

function loadData<T>(key: string): T | null {
  const namespacedKey = `${NAMESPACE}:${key}`;
  const jsonData = storage.get(namespacedKey, StoreType.STRING) as string;

  return jsonData ? JSON.parse(jsonData) : null;
}

function saveTypes(
  typesData: { type: number; name: string }[],
  startIndexes: Record<string, number>
): void {
  const types: TypeData[] = typesData.map((item) => ({
    ...item,
    start: startIndexes[item.type]
  }));
  saveData<TypeData[]>('types', types);
}

function saveTypeMasters(type: number, masters: Master[]): void {
  let allMasters: Record<number, Master[]> = loadData<Record<number, Master[]>>('masters') || {};
  allMasters[type] = masters;
  saveData('masters', allMasters);
}

function saveSort(filtersData: any, filterType: 'yearOfCompletion' | 'countryOfOrigin'): void {
  const filters = filtersData.reduce((obj: any, item: any) => {
    const key = filterType === 'yearOfCompletion' ? item.year : item.country;
    obj[key] = item.masters.map((master: Master) => master.id);

    return obj;
  }, {});
  saveData<SortData>(filterType, filters);
}

async function handleGetTypeResponse(type: number): Promise<number | null> {
  const responseData = await fetchUNMastersType(type);
  if (responseData && responseData.result === 'OK') {
    saveTypeMasters(type, (responseData.data as { data: Master[] }).data);

    return (responseData.data as { start: number }).start;
  }

  return null;
}

export async function fetchAndSaveAllTypesAndMasters() {
  const typesResponse = await fetchUNMastersTypes();
  const startIndexes: Record<string, number> = {};

  if (typesResponse && typesResponse.result === 'OK') {
    const types = typesResponse.data.map((type) => type.type);
    for (let type of types) {
      const startIndex = await handleGetTypeResponse(type);
      if (startIndex !== null) {
        startIndexes[type] = startIndex;
      }
    }
    saveTypes(typesResponse.data, startIndexes);
  }

  const countryResponse = await fetchUNMastersType(-1);
  const yearResponse = await fetchUNMastersType(-2);

  if (yearResponse && yearResponse.result === 'OK') {
    saveSort(yearResponse.data, 'yearOfCompletion');
  }

  if (countryResponse && countryResponse.result === 'OK') {
    saveSort(countryResponse.data, 'countryOfOrigin');
  }
}

export function getMastersByCountryOfOrigin() {
  const countrySortData = loadData('countryOfOrigin');
  if (!countrySortData) return null;

  const countryBlocks: { country: string; count: number; masters: Master[] }[] = [];

  for (const [country, masterIds] of Object.entries(countrySortData)) {
    const mastersList: Master[] = [];
    masterIds.forEach((id: number) => {
      const master = getMasterById(id);
      if (master) {
        mastersList.push(master);
      }
    });

    countryBlocks.push({
      country,
      count: mastersList?.length ?? 0,
      masters: mastersList ?? []
    });
  }

  return countryBlocks;
}

export function getMastersByYearOfCompletion() {
  const yearSortData = loadData('yearOfCompletion');
  if (!yearSortData) return null;

  const yearBlocks: { year: string; count: number; masters: Master[] }[] = [];

  for (const [year, masterIds] of Object.entries(yearSortData)) {
    const mastersList: Master[] = [];
    masterIds.forEach((id: number) => {
      const master = getMasterById(id);
      if (master) {
        mastersList.push(master);
      }
    });

    yearBlocks.push({
      year,
      count: mastersList?.length ?? 0,
      masters: mastersList ?? []
    });
  }

  return yearBlocks;
}

export function getMastersByType(type: number) {
  const allMasters: MastersData | null = loadData('masters');
  if (!allMasters) return null;

  return allMasters[type] || [];
}

function getMasterById(id: number) {
  const allMasters = loadData('masters');
  if (!allMasters) return null;

  for (const typeMasters of Object.values(allMasters)) {
    const master = typeMasters.find((m: Master) => m.id === id);
    if (master) return master;
  }

  return null;
}

export function getUNMastersTypes() {
  const types = loadData<TypeData[]>('types');
  if (!types) return null;

  return types;
}

export interface Master {
  id: number;
  type: number;
  origin: string;
  origin1: string;
  origin2: string;
  full_name: string;
  tbt_username: string;
  born: string;
  final: string | null;
  final_year: string;
  final_country: string;
  age: string;
  personal: string;
  media: string;
  media2: string;
  media3: string;
  wikipedia: string;
  book: string;
  book_url: string;
  book2: string;
  book_url2: string;
  social: string;
  twitter: string;
  instagram: string;
  youtube: string;
  status: number;
  sort: number;
  last_country: string;
  user_id: number | null;
  origin1_flag: string;
  origin2_flag: string | null;
  final_flag: string;
  interviews: string[];
}

export interface TypeData {
  name: string;
  start: number;
  type: number;
}

interface SortData {
  [key: string]: number[];
}

export interface MastersData {
  [key: string]: Master[];
}
