import { authInstance, languageInstance, mobxFetch } from "@shared";
import { makeAutoObservable, runInAction } from "mobx";
import { getVehicleSessionsApi } from "./api";
import { Vehicle, VehicleMaintenanceSession } from "./types";

export type { Vehicle, VehicleMaintenanceSession } from "./types";

class VehicleStore {
  vehicles: {
    data: Vehicle[];
    loaded: boolean;
  } = {
    data: [],
    loaded: false,
  };
  vehicle: Record<string, Vehicle> = {};
  vehicleSessions: VehicleMaintenanceSession[] | null = null;
  vehicleSessionsLoading = false;
  vehicleSessionsError: string | null = null;

  constructor() {
    makeAutoObservable(this);
  }

  private normalizeVehicleItem = (item: any): Vehicle => {
    if (item && typeof item === "object" && "vehicle" in item) {
      return {
        vehicle: item.vehicle ?? {},
        device_status: item.device_status,
      } as Vehicle;
    }

    return {
      vehicle: item ?? {},
    } as Vehicle;
  };

  private mergeVehicleInCaches = (updatedVehicle: any) => {
    if (!updatedVehicle) return;

    const updatedId = updatedVehicle.id;
    const updatedUuid = updatedVehicle.uuid;

    const mergeItem = (item: Vehicle): Vehicle => ({
      ...item,
      vehicle: {
        ...item.vehicle,
        ...updatedVehicle,
      },
    });

    this.vehicles.data = this.vehicles.data.map((item) => {
      const sameId = updatedId != null && item.vehicle.id === updatedId;
      const sameUuid =
        updatedUuid != null &&
        item.vehicle.uuid != null &&
        item.vehicle.uuid === updatedUuid;

      if (!sameId && !sameUuid) return item;

      return mergeItem(item);
    });

    if (updatedId != null) {
      const existing = this.vehicle[updatedId];
      this.vehicle[updatedId] = existing
        ? mergeItem(existing)
        : ({ vehicle: updatedVehicle } as Vehicle);
      return;
    }

    if (updatedUuid != null) {
      const entry = Object.entries(this.vehicle).find(
        ([, item]) => item.vehicle.uuid === updatedUuid,
      );

      if (entry) {
        const [key, item] = entry;
        this.vehicle[key] = mergeItem(item);
      }
    }
  };

  getVehicles = async () => {
    const response = await languageInstance("ru").get(`/vehicle`);
    const vehiclesList = Array.isArray(response.data)
      ? response.data
      : Array.isArray(response.data?.vehicles)
        ? response.data.vehicles
        : [];

    runInAction(() => {
      this.vehicles.data = vehiclesList.map(this.normalizeVehicleItem);
      this.vehicles.loaded = true;
    });
  };

  deleteVehicle = async (id: number) => {
    await languageInstance("ru").delete(`/vehicle/${id}`);

    runInAction(() => {
      this.vehicles.data = this.vehicles.data.filter(
        (vehicle) => vehicle.vehicle.id !== id,
      );
    });
  };

  getVehicle = async (id: number) => {
    const response = await languageInstance("ru").get(`/vehicle/${id}`);
    const normalizedVehicle = this.normalizeVehicleItem(response.data);

    runInAction(() => {
      this.vehicle[id] = normalizedVehicle;
    });
  };

  createVehicle = async (
    tailNumber: string,
    type: number,
    carrier: string,
    carrierId: number,
    model?: string,
    cityId?: number,
  ) => {
    const payload: Record<string, unknown> = {
      tail_number: tailNumber.trim(),
      type,
      carrier: carrier.trim(),
      carrier_id: carrierId,
    };
    // TODO: когда будет бекенд — добавить model в payload и в ответ
    if (model != null && model !== "") payload.model = model;
    if (cityId != null) payload.city_id = cityId;
    const response = await languageInstance("ru").post("/vehicle", payload);
    const normalizedVehicle = this.normalizeVehicleItem(response.data);

    runInAction(() => {
      this.vehicles.data.push(normalizedVehicle);
      if (normalizedVehicle.vehicle?.id != null) {
        this.vehicle[normalizedVehicle.vehicle.id] = normalizedVehicle;
      }
    });
  };

  editVehicleData: {
    tail_number: string;
    type: number;
    carrier: string;
    carrier_id: number;
    model: string;
    snapshot_update_blocked: boolean;
    city_id?: number;
  } = {
    tail_number: "",
    type: 0,
    carrier: "",
    carrier_id: 0,
    model: "",
    snapshot_update_blocked: false,
    city_id: undefined,
  };

  setEditVehicleData = (data: {
    tail_number: string;
    type: number;
    carrier: string;
    carrier_id: number;
    model?: string;
    snapshot_update_blocked?: boolean;
    city_id?: number;
  }) => {
    this.editVehicleData = {
      ...this.editVehicleData,
      ...data,
    };
  };

  editVehicle = async (
    id: number,
    data: {
      tail_number: string;
      type: number;
      carrier: string;
      carrier_id: number;
      model?: string;
      snapshot_update_blocked?: boolean;
      city_id?: number;
    },
  ) => {
    const payload: Record<string, unknown> = {
      tail_number: data.tail_number.trim(),
      type: data.type,
      carrier: data.carrier.trim(),
      carrier_id: data.carrier_id,
    };
    if (data.model != null && data.model !== "") payload.model = data.model;
    if (data.snapshot_update_blocked != null)
      payload.snapshot_update_blocked = data.snapshot_update_blocked;
    if (data.city_id != null) payload.city_id = data.city_id;
    const response = await languageInstance("ru").patch(
      `/vehicle/${id}`,
      payload,
    );
    const normalizedVehicle = this.normalizeVehicleItem(response.data);
    const updatedVehiclePayload = {
      ...normalizedVehicle.vehicle,
      model: normalizedVehicle.vehicle.model ?? data.model,
      snapshot_update_blocked:
        normalizedVehicle.vehicle.snapshot_update_blocked ??
        data.snapshot_update_blocked,
    };

    runInAction(() => {
      this.mergeVehicleInCaches({
        ...updatedVehiclePayload,
        id,
      });
    });
  };

  setMaintenanceMode = async (uuid: string, enabled: boolean) => {
    const response = await authInstance.post(
      `/devices/${uuid}/maintenance-mode`,
      {
        enabled,
      },
    );
    const normalizedVehicle = this.normalizeVehicleItem(response.data);

    runInAction(() => {
      this.mergeVehicleInCaches({
        ...normalizedVehicle.vehicle,
        uuid,
        maintenance_mode_on:
          normalizedVehicle.vehicle.maintenance_mode_on ?? enabled,
      });
    });
  };

  setDemoMode = async (uuid: string, enabled: boolean) => {
    const response = await authInstance.post(`/devices/${uuid}/demo-mode`, {
      enabled,
    });
    const normalizedVehicle = this.normalizeVehicleItem(response.data);

    runInAction(() => {
      this.mergeVehicleInCaches({
        ...normalizedVehicle.vehicle,
        uuid,
        demo_mode_enabled:
          normalizedVehicle.vehicle.demo_mode_enabled ?? enabled,
      });
    });
  };

  getVehicleSessions = mobxFetch<
    number,
    VehicleMaintenanceSession[],
    VehicleStore
  >({
    store: this,
    value: "vehicleSessions",
    loading: "vehicleSessionsLoading",
    error: "vehicleSessionsError",
    resetValue: true,
    fn: getVehicleSessionsApi,
  });
}

export const vehicleStore = new VehicleStore();
