import { authInstance, mobxFetch } from "@shared";
import { makeAutoObservable, runInAction } from "mobx";
import { addUserCityApi } from "./api";

export type UserCity = {
  city_id: number;
  name: string;
};

export type User = {
  id: number;
  email: string;
  is_admin: boolean;
  name: string;
  password?: string;
  icon?: string;
  roles?: string[];
  cities?: UserCity[];
};

class UserStore {
  users: {
    data: User[];
    loaded: boolean;
  } = {
    data: [],
    loaded: false,
  };
  user: Record<string, User> = {};

  constructor() {
    makeAutoObservable(this);
  }

  getUsers = async () => {
    const response = await authInstance.get("/user");

    runInAction(() => {
      this.users.data = response.data;
      this.users.loaded = true;
    });
  };

  getUser = async (id: number) => {
    if (this.user[id]) return this.user[id];
    const response = await authInstance.get(`/user/${id}`);

    runInAction(() => {
      this.user[id] = response.data as User;
    });

    return response.data;
  };

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

    runInAction(() => {
      this.users.data = this.users.data.filter((user) => user.id !== id);
      delete this.user[id];
    });
  };

  createUserData: Partial<User> = {
    name: "",
    email: "",
    password: "",
    is_admin: false,
    icon: "",
    roles: ["articles_ro", "articles_rw", "media_ro", "media_rw"],
  };

  setCreateUserData = (
    name: string,
    email: string,
    password: string,
    is_admin: boolean,
    icon?: string,
  ) => {
    this.createUserData = {
      ...this.createUserData,
      name,
      email,
      password,
      is_admin,
      icon: icon ?? "",
    };
  };

  createUser = async () => {
    let id = 1;
    if (this.users.data.length > 0) {
      id = this.users.data[this.users.data.length - 1].id + 1;
    }
    const payload: Partial<User> = {
      ...this.createUserData,
      name: (this.createUserData.name || "").trim(),
      email: (this.createUserData.email || "").trim(),
    };
    const baseRoles = new Set<string>(payload.roles ?? []);
    baseRoles.add("articles_ro");
    baseRoles.add("articles_rw");
    baseRoles.add("media_ro");
    baseRoles.add("media_rw");
    payload.roles = Array.from(baseRoles);
    if (!payload.icon) delete payload.icon;
    const response = await authInstance.post("/user", payload);

    runInAction(() => {
      this.users.data.push({
        id: id,
        ...response.data,
      });
    });
  };

  editUserData: Partial<User> = {
    name: "",
    email: "",
    password: "",
    is_admin: false,
    icon: "",
    roles: [],
  };

  setEditUserData = (
    name: string,
    email: string,
    password: string,
    is_admin: boolean,
    icon?: string,
  ) => {
    this.editUserData = {
      ...this.editUserData,
      name,
      email,
      password,
      is_admin,
      icon: icon ?? "",
    };
  };

  setEditUserRoles = (roles: string[]) => {
    this.editUserData = { ...this.editUserData, roles };
  };

  editUser = async (id: number) => {
    const payload = {
      ...this.editUserData,
      name: (this.editUserData.name || "").trim(),
      email: (this.editUserData.email || "").trim(),
    };
    if (!payload.icon) delete payload.icon;
    if (!payload.password?.trim()) delete payload.password;

    const response = await authInstance.patch(`/user/${id}`, payload);

    runInAction(() => {
      this.users.data = this.users.data.map((user) =>
        user.id === id ? { ...user, ...response.data } : user,
      );
      this.user[id] = { ...this.user[id], ...response.data };
    });
  };

  addUserCityResult: User | null = null;
  addUserCityLoading = false;
  addUserCityError: string | null = null;

  addUserCityAction = mobxFetch<
    { id: number; city_ids: number[] },
    User,
    UserStore
  >({
    store: this,
    value: "addUserCityResult",
    loading: "addUserCityLoading",
    error: "addUserCityError",
    fn: addUserCityApi,
    onSuccess: (result) => {
      runInAction(() => {
        this.users.data = this.users.data.map((user) =>
          user.id === result.id ? { ...user, ...result } : user,
        );
        if (this.user[result.id]) {
          this.user[result.id] = { ...this.user[result.id], ...result };
        }
      });
    },
  });
}

export const userStore = new UserStore();
