import { authInstance, languageInstance, languageStore } from "@shared";
import { makeAutoObservable, runInAction } from "mobx";
import { routeStore } from "../RouteStore";

type Language = "ru" | "en" | "zh";

type StationLanguageData = {
  name: string;
  system_name: string;
  address: string;
  loaded: boolean;
};

type StationCommonData = {
  city_id: number;
  description: string;
  icon: string;
  latitude: number;
  longitude: number;
  offset_x: number;
  offset_y: number;
  transfers: {
    bus: string;
    metro_blue: string;
    metro_green: string;
    metro_orange: string;
    metro_purple: string;
    metro_red: string;
    train: string;
    tram: string;
    trolleybus: string;
  };
  city: string;
};

type EditStationData = {
  [key in Language]: StationLanguageData;
} & { common: StationCommonData };

type Station = {
  id: number;
  address: string;
  city: string;
  city_id: number;
  description: string;
  icon: string;
  latitude: number;
  longitude: number;
  name: string;
  offset_x: number;
  offset_y: number;
  system_name: string;
  transfers: {
    bus: string;
    metro_blue: string;
    metro_green: string;
    metro_orange: string;
    metro_purple: string;
    metro_red: string;
    train: string;
    tram: string;
    trolleybus: string;
  };
};

type CreateStationData = {
  [key in Language]: StationLanguageData;
} & { common: StationCommonData };

class StationsStore {
  stations: Station[] = [];
  station: Station | null = null;

  sightCounts: Map<number, number> = new Map();
  sightCountsLoading = false;

  stationLists: {
    [key in Language]: {
      data: Station[];
      loaded: boolean;
    };
  } = {
    ru: {
      data: [],
      loaded: false,
    },
    en: {
      data: [],
      loaded: false,
    },
    zh: {
      data: [],
      loaded: false,
    },
  };

  stationPreview: Record<
    string,
    Record<string, { loaded: boolean; data: Station }>
  > = {};

  editStationData: EditStationData = {
    ru: {
      name: "",
      system_name: "",

      address: "",
      loaded: false,
    },
    en: {
      name: "",
      system_name: "",

      address: "",
      loaded: false,
    },
    zh: {
      name: "",
      system_name: "",

      address: "",
      loaded: false,
    },
    common: {
      city: "",
      city_id: 0,
      description: "",
      icon: "",
      latitude: 0,
      longitude: 0,
      offset_x: 0,
      offset_y: 0,
      transfers: {
        bus: "",
        metro_blue: "",
        metro_green: "",
        metro_orange: "",
        metro_purple: "",
        metro_red: "",
        train: "",
        tram: "",
        trolleybus: "",
      },
    },
  };

  createStationData: CreateStationData = {
    ru: {
      name: "",
      system_name: "",

      address: "",
      loaded: false,
    },
    en: {
      name: "",
      system_name: "",

      address: "",
      loaded: false,
    },
    zh: {
      name: "",
      system_name: "",

      address: "",
      loaded: false,
    },
    common: {
      city: "",
      city_id: 0,
      description: "",
      icon: "",
      latitude: 0,
      longitude: 0,
      offset_x: 0,
      offset_y: 0,
      transfers: {
        bus: "",
        metro_blue: "",
        metro_green: "",
        metro_orange: "",
        metro_purple: "",
        metro_red: "",
        train: "",
        tram: "",
        trolleybus: "",
      },
    },
  };

  constructor() {
    makeAutoObservable(this);
  }

  getStations = async () => {
    const response = await authInstance.get("/station");

    runInAction(() => {
      this.stations = response.data;
    });
  };

  getStationList = async () => {
    const { language } = languageStore;
    if (this.stationLists[language].loaded) {
      return;
    }
    const response = await authInstance.get("/station");

    runInAction(() => {
      this.stationLists[language].data = response.data;
      this.stationLists[language].loaded = true;
    });
  };

  loadSightCounts = async (stationIds: number[]) => {
    if (stationIds.length === 0) return;

    runInAction(() => {
      this.sightCountsLoading = true;
    });

    const batchSize = 20;
    for (let i = 0; i < stationIds.length; i += batchSize) {
      const batch = stationIds.slice(i, i + batchSize);
      const results = await Promise.allSettled(
        batch.map((id) =>
          authInstance
            .get(`/station/${id}/sight/count`)
            .then((res) => ({ id, data: res.data }))
        )
      );

      runInAction(() => {
        for (const result of results) {
          if (result.status === "fulfilled") {
            const { id, data } = result.value;
            let count = 0;
            if (typeof data === "number") {
              count = data;
            } else if (data && typeof data === "object") {
              count = Object.values(data).reduce((sum: number, v: any) => sum + (Number(v) || 0), 0);
            }
            this.sightCounts.set(id, count);
          }
        }
      });
    }

    runInAction(() => {
      this.sightCountsLoading = false;
    });
  };

  setEditCommonData = (data: Partial<StationCommonData>) => {
    this.editStationData.common = {
      ...this.editStationData.common,
      ...data,
    };
  };

  getEditStation = async (id: number) => {
    const ruResponse = await languageInstance("ru").get(`/station/${id}`);
    const enResponse = await languageInstance("en").get(`/station/${id}`);
    const zhResponse = await languageInstance("zh").get(`/station/${id}`);

    this.editStationData = {
      ru: {
        name: ruResponse.data.name,
        system_name: ruResponse.data.system_name,

        address: ruResponse.data.address,
        loaded: true,
      },
      en: {
        name: enResponse.data.name,
        system_name: enResponse.data.system_name,

        address: enResponse.data.address,
        loaded: true,
      },
      zh: {
        name: zhResponse.data.name,
        system_name: zhResponse.data.system_name,

        address: zhResponse.data.address,
        loaded: true,
      },
      common: {
        city: ruResponse.data.city,
        city_id: ruResponse.data.city_id,
        description: ruResponse.data.description,
        icon: ruResponse.data.icon,
        latitude: ruResponse.data.latitude,
        longitude: ruResponse.data.longitude,
        offset_x: ruResponse.data.offset_x,
        offset_y: ruResponse.data.offset_y,
        transfers: ruResponse.data.transfers,
      },
    };
  };

  setLanguageEditStationData = (
    language: Language,
    data: Partial<StationLanguageData>
  ) => {
    this.editStationData[language] = {
      ...this.editStationData[language],
      ...data,
    };
  };

  editStation = async (id: number) => {
    const commonDataPayload = {
      city_id: this.editStationData.common.city_id,
      icon: this.editStationData.common.icon,
      latitude: this.editStationData.common.latitude,
      longitude: this.editStationData.common.longitude,
      offset_x: this.editStationData.common.offset_x,
      offset_y: this.editStationData.common.offset_y,
      transfers: this.editStationData.common.transfers,
      city: this.editStationData.common.city,
    };

    for (const language of ["ru", "en", "zh"] as const) {
      const { name, address } = this.editStationData[language];
      const description = this.editStationData.common.description;
      const response = await languageInstance(language).patch(
        `/station/${id}`,
        {
          name: (name || "").trim(),
          system_name: (name || "").trim(),
          description: (description || "").trim(),
          address: (address || "").trim(),
          ...commonDataPayload,
        }
      );

      runInAction(() => {
        if (this.stationPreview[id]) {
          this.stationPreview[id][language] = {
            loaded: true,
            data: {
              ...this.stationPreview[id][language].data,
              id: response.data.id,
              name: response.data.name,
              system_name: response.data.system_name,
              description: response.data.description,
              address: response.data.address,
              ...commonDataPayload,
            } as Station,
          };
        }
        if (this.stationLists[language].data) {
          this.stationLists[language].data = this.stationLists[
            language
          ].data.map((station: Station) =>
            station.id === id
              ? ({
                  ...station,
                  name: response.data.name,
                  system_name: response.data.system_name,
                  description: description || "",
                  address: response.data.address,
                  ...commonDataPayload,
                } as Station)
              : station
          );
        }
      });
    }
  };

  deleteStation = async (id: number) => {
    await authInstance.delete(`/station/${id}`);

    runInAction(() => {
      this.stations = this.stations.filter((station) => station.id !== id);

      if (this.stationPreview[id]) {
        delete this.stationPreview[id];
      }

      for (const lang of ["ru", "en", "zh"] as const) {
        if (this.stationLists[lang].data) {
          this.stationLists[lang].data = this.stationLists[lang].data.filter(
            (station) => station.id !== id
          );
        }
      }
    });
  };

  getStation = async (id: number) => {
    const response = await authInstance.get(`/station/${id}`);
    this.station = response.data;
  };

  getStationPreview = async (id: number) => {
    const { language } = languageStore;

    if (this.stationPreview[id]?.[language]?.loaded) {
      return;
    }

    const response = await languageInstance(language).get(`/station/${id}`);
    runInAction(() => {
      if (!this.stationPreview[id]) {
        this.stationPreview[id] = {
          ru: { loaded: false, data: {} as Station },
          en: { loaded: false, data: {} as Station },
          zh: { loaded: false, data: {} as Station },
        };
      }
      this.stationPreview[id][language] = {
        loaded: true,
        data: response.data as Station,
      };
    });
  };

  setCreateCommonData = (data: Partial<StationCommonData>) => {
    this.createStationData.common = {
      ...this.createStationData.common,
      ...data,
    };
  };

  setLanguageCreateStationData = (
    language: Language,
    data: Partial<StationLanguageData>
  ) => {
    this.createStationData[language] = {
      ...this.createStationData[language],
      ...data,
    };
  };

  createStation = async () => {
    const { language } = languageStore;
    let commonDataPayload: Partial<StationCommonData> = {
      city_id: this.createStationData.common.city_id,
      icon: this.createStationData.common.icon,
      latitude: this.createStationData.common.latitude,
      longitude: this.createStationData.common.longitude,
      offset_x: this.createStationData.common.offset_x,
      offset_y: this.createStationData.common.offset_y,
      transfers: this.createStationData.common.transfers,
      city: this.createStationData.common.city,
    };

    if (this.createStationData.common.icon === "") {
      delete commonDataPayload.icon;
    }

    const { name, address } = this.createStationData[language];
    const description = this.createStationData.common.description;
    const response = await languageInstance(language).post("/station", {
      name: (name || "").trim(),
      system_name: (name || "").trim(),
      description: (description || "").trim(),
      address: (address || "").trim(),
      ...commonDataPayload,
    });

    runInAction(() => {
      this.stationLists[language].data.push(response.data);
    });

    const stationId: number = response.data.id;

    for (const lang of ["ru", "en", "zh"].filter(
      (lang) => lang !== language
    ) as Language[]) {
      const { name, address } = this.createStationData[lang];
      const description = this.createStationData.common.description;
      const response = await languageInstance(lang).patch(
        `/station/${stationId}`,
        {
          name: (name || "").trim(),
          system_name: (name || "").trim(),
          description: (description || "").trim(),
          address: (address || "").trim(),
          ...commonDataPayload,
        }
      );

      runInAction(() => {
        this.stationLists[lang].data.push(response.data);
      });
    }

    runInAction(() => {
      this.createStationData = {
        ru: {
          name: "",
          system_name: "",
          address: "",
          loaded: false,
        },
        en: {
          name: "",
          system_name: "",
          address: "",
          loaded: false,
        },
        zh: {
          name: "",
          system_name: "",
          address: "",
          loaded: false,
        },
        common: {
          city: "",
          city_id: 0,
          icon: "",
          latitude: 0,
          description: "",
          longitude: 0,
          offset_x: 0,
          offset_y: 0,
          transfers: {
            bus: "",
            metro_blue: "",
            metro_green: "",
            metro_orange: "",
            metro_purple: "",
            metro_red: "",
            train: "",
            tram: "",
            trolleybus: "",
          },
        },
      };
    });
    return response.data;
  };

  resetEditStationData = () => {
    this.editStationData = {
      ru: {
        name: "",
        system_name: "",
        address: "",
        loaded: false,
      },
      en: {
        name: "",
        system_name: "",
        address: "",
        loaded: false,
      },
      zh: {
        name: "",
        system_name: "",
        address: "",
        loaded: false,
      },
      common: {
        city: "",
        city_id: 0,
        description: "",
        icon: "",
        latitude: 0,
        longitude: 0,
        offset_x: 0,
        offset_y: 0,
        transfers: {
          bus: "",
          metro_blue: "",
          metro_green: "",
          metro_orange: "",
          metro_purple: "",
          metro_red: "",
          train: "",
          tram: "",
          trolleybus: "",
        },
      },
    };
  };

  updateStationTransfers = async (
    id: number,
    transfers: {
      bus: string;
      metro_blue: string;
      metro_green: string;
      metro_orange: string;
      metro_purple: string;
      metro_red: string;
      train: string;
      tram: string;
      trolleybus: string;
    }
  ) => {
    const { language } = languageStore;

    const response = await languageInstance(language).get(`/station/${id}`);
    const stationData = response.data as Station;

    if (!stationData) {
      throw new Error("Station not found");
    }

    // Формируем commonDataPayload как в editStation, с обновленными transfers
    const commonDataPayload = {
      city_id: stationData.city_id,
      latitude: stationData.latitude,
      longitude: stationData.longitude,
      offset_x: stationData.offset_x,
      offset_y: stationData.offset_y,
      transfers: transfers,
      city: stationData.city || "",
    };

    // Отправляем один PATCH запрос, так как пересадки общие для всех языков
    const patchResponse = await languageInstance(language).patch(
      `/station/${id}`,
      {
        name: stationData.name || "",
        system_name: stationData.system_name || "",
        description: stationData.description || "",
        address: stationData.address || "",
        ...commonDataPayload,
      }
    );

    // Обновляем данные для всех языков в локальном состоянии
    runInAction(() => {
      const updatedTransfers = patchResponse.data.transfers;

      for (const lang of ["ru", "en", "zh"] as const) {
        if (this.stationPreview[id]) {
          this.stationPreview[id][lang] = {
            ...this.stationPreview[id][lang],
            data: {
              ...this.stationPreview[id][lang].data,
              transfers: updatedTransfers,
            },
          };
        }
        if (this.stationLists[lang].data) {
          this.stationLists[lang].data = this.stationLists[lang].data.map(
            (station: Station) =>
              station.id === id
                ? {
                    ...station,
                    transfers: updatedTransfers,
                  }
                : station
          );
        }
      }

      // Обновляем пересадки в RouteStore.routeStations для всех маршрутов
      if (routeStore?.routeStations) {
        for (const routeId in routeStore.routeStations) {
          routeStore.routeStations[routeId] = routeStore.routeStations[
            routeId
          ].map((station: any) =>
            station.id === id
              ? {
                  ...station,
                  transfers: updatedTransfers,
                }
              : station
          );
        }
      }
    });
  };
}

export const stationsStore = new StationsStore();
