import { api } from '@flaschengeist/api';
import { defineStore } from 'pinia';
import { calc_volume, calc_cost_per_volume, calc_all_min_prices } from './utils/utils';
import Ingredient = FG.Ingredient;

interface DrinkPriceVolume extends Omit<FG.DrinkPriceVolume, 'volume'> {
  _volume: number;
  volume?: number;
}

interface Drink extends Omit<Omit<FG.Drink, 'cost_per_volume'>, 'volumes'> {
  volumes: DrinkPriceVolume[];
  cost_per_volume?: number;
  _cost_per_volume?: number;
}

interface Pricelist {
  name: string;
  type: FG.DrinkType;
  tags: Array<FG.Tag>;
  volume: number;
  price: number;
  public: boolean;
  description: string;
}

class DrinkPriceVolume implements DrinkPriceVolume {
  constructor({ id, volume, prices, ingredients }: FG.DrinkPriceVolume) {
    this.id = id;
    this._volume = volume;
    this.prices = prices;
    this.ingredients = ingredients;
    this.min_prices = [];
    this.volume = calc_volume(this);
  }
}

class Drink {
  constructor({
    id,
    article_id,
    package_size,
    name,
    volume,
    cost_per_volume,
    cost_per_package,
    tags,
    type,
    uuid,
    receipt,
  }: FG.Drink) {
    this.id = id;
    this.article_id = article_id;
    this.package_size = package_size;
    this.name = name;
    this.volume = volume;
    this.cost_per_package = cost_per_package;
    this._cost_per_volume = cost_per_volume;
    this.cost_per_volume = calc_cost_per_volume(this);
    this.tags = tags;
    this.type = type;
    this.volumes = [];
    this.uuid = uuid;
    this.receipt = receipt || [];
  }
}

interface Order {
  label: string;
  name: string;
}

export const usePricelistStore = defineStore({
  id: 'pricelist',

  state: () => ({
    drinkTypes: [] as Array<FG.DrinkType>,
    drinks: [] as Array<Drink>,
    extraIngredients: [] as Array<FG.ExtraIngredient>,
    min_prices: [] as Array<number>,
    tags: [] as Array<FG.Tag>,
    pricecalc_columns: [] as Array<string>,
    pricelist_view: false as boolean,
    pricelist_columns_order: [] as Array<Order>,
  }),

  actions: {
    async getDrinkTypes(force = false) {
      if (force || this.drinks.length == 0) {
        const { data } = await api.get<Array<FG.DrinkType>>('/pricelist/drink-types');
        this.drinkTypes = data;
      }
      return this.drinkTypes;
    },
    async addDrinkType(name: string) {
      const { data } = await api.post<FG.DrinkType>('/pricelist/drink-types', { name: name });
      this.drinkTypes.push(data);
    },
    async removeDrinkType(id: number) {
      await api.delete(`/pricelist/drink-types/${id}`);
      const idx = this.drinkTypes.findIndex((val) => val.id == id);
      if (idx >= 0) this.drinkTypes.splice(idx, 1);
    },
    async changeDrinkTypeName(drinkType: FG.DrinkType) {
      await api.put(`/pricelist/drink-types/${drinkType.id}`, drinkType);
      const itm = this.drinkTypes.filter((val) => val.id == drinkType.id);
      if (itm.length > 0) itm[0].name = drinkType.name;
    },
    async getExtraIngredients() {
      const { data } = await api.get<Array<FG.ExtraIngredient>>(
        'pricelist/ingredients/extraIngredients'
      );
      this.extraIngredients = data;
    },
    async setExtraIngredient(ingredient: FG.ExtraIngredient) {
      const { data } = await api.post<FG.ExtraIngredient>(
        'pricelist/ingredients/extraIngredients',
        ingredient
      );
      this.extraIngredients.push(data);
    },
    async updateExtraIngredient(ingredient: FG.ExtraIngredient) {
      const { data } = await api.put<FG.ExtraIngredient>(
        `pricelist/ingredients/extraIngredients/${ingredient.id}`,
        ingredient
      );
      const index = this.extraIngredients.findIndex((a) => a.id === ingredient.id);
      if (index > -1) {
        this.extraIngredients[index] = data;
      } else {
        this.extraIngredients.push(data);
      }
    },
    async deleteExtraIngredient(ingredient: FG.ExtraIngredient) {
      await api.delete(`pricelist/ingredients/extraIngredients/${ingredient.id}`);
      const index = this.extraIngredients.findIndex((a) => a.id === ingredient.id);
      if (index > -1) {
        this.extraIngredients.splice(index, 1);
      }
    },
    async getDrinks(filter: { limit?: number; offset?: number; descending?: boolean }) {
      if (!filter) filter = { limit: 10 };
      const { data } = await api.get<Array<FG.Drink>>('pricelist/drinks', {
        params: filter,
      });
      this.drinks = [];
      data.drinks.forEach((drink) => {
        const _drink = new Drink(drink);
        drink.volumes.forEach((volume) => {
          const _volume = new DrinkPriceVolume(volume);
          _drink.volumes.push(_volume);
        });
        this.drinks.push(_drink);
      });
      calc_all_min_prices(this.drinks, this.min_prices);
      return data;
    },
    sortPrices(volume: DrinkPriceVolume) {
      volume.prices.sort((a, b) => {
        if (a.price > b.price) return 1;
        if (b.price > a.price) return -1;
        return 0;
      });
    },
    async deletePrice(price: FG.DrinkPrice) {
      await api.delete(`pricelist/prices/${price.id}`);
    },
    async deleteVolume(volume: DrinkPriceVolume, drink: Drink) {
      await api.delete(`pricelist/volumes/${volume.id}`);
      const index = drink.volumes.findIndex((a) => a.id === volume.id);
      if (index > -1) {
        drink.volumes.splice(index, 1);
      }
    },
    async deleteIngredient(ingredient: FG.Ingredient) {
      await api.delete(`pricelist/ingredients/${ingredient.id}`);
    },
    async setDrink(drink: Drink) {
      const { data } = await api.post<FG.Drink>('pricelist/drinks', {
        ...drink,
      });
      const _drink = new Drink(data);
      data.volumes.forEach((volume) => {
        const _volume = new DrinkPriceVolume(volume);
        _drink.volumes.push(_volume);
      });
      this.drinks.push(_drink);
      calc_all_min_prices(this.drinks, this.min_prices);
      return _drink;
    },
    async updateDrink(drink: Drink) {
      const { data } = await api.put<FG.Drink>(`pricelist/drinks/${drink.id}`, {
        ...drink,
      });
      const index = this.drinks.findIndex((a) => a.id === data.id);
      if (index > -1) {
        const _drink = new Drink(data);
        data.volumes.forEach((volume) => {
          const _volume = new DrinkPriceVolume(volume);
          _drink.volumes.push(_volume);
        });
        this.drinks[index] = _drink;
      }
      if (!!drink.cost_per_volume) {
        this.drinks.forEach((_drink: Drink) => {
          _drink.volumes.forEach((_volume: DrinkPriceVolume) => {
            _volume.ingredients.forEach((_ingredient: Ingredient) => {
              if (
                _ingredient.drink_ingredient &&
                _ingredient.drink_ingredient.ingredient_id === drink.id
              ) {
                _ingredient.drink_ingredient.cost_per_volume = drink.cost_per_volume;
                _ingredient.drink_ingredient.name = drink.name;
              }
            });
          });
        });
      }
      calc_all_min_prices(this.drinks, this.min_prices);
    },
    deleteDrink(drink: Drink) {
      api
        .delete(`pricelist/drinks/${drink.id}`)
        .then(() => {
          const index = this.drinks.findIndex((a) => a.id === drink.id);
          if (index > -1) {
            this.drinks.splice(index, 1);
          }
        })
        .catch((err) => console.warn(err));
    },
    async get_min_prices() {
      const { data } = await api.get<Array<number>>('pricelist/settings/min_prices');
      this.min_prices = data;
    },
    async set_min_prices() {
      await api.post<Array<number>>('pricelist/settings/min_prices', this.min_prices);
      calc_all_min_prices(this.drinks, this.min_prices);
    },
    async upload_drink_picture(drink: Drink, file: File) {
      const formData = new FormData();
      formData.append('file', file);
      const { data } = await api.post<FG.Drink>(`pricelist/drinks/${drink.id}/picture`, formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      });
      const _drink = this.drinks.find((a) => a.id === drink.id);
      if (_drink) {
        _drink.uuid = data.uuid;
      }
    },
    async delete_drink_picture(drink: Drink) {
      await api.delete(`pricelist/drinks/${drink.id}/picture`);
      drink.uuid = '';
    },
    async getTags() {
      const { data } = await api.get<Array<FG.Tag>>('/pricelist/tags');
      this.tags = data;
    },
    async setTag(tag: FG.Tag) {
      const { data } = await api.post<FG.Tag>('/pricelist/tags', tag);
      this.tags.push(data);
    },
    async updateTag(tag: FG.Tag) {
      const { data } = await api.put<FG.Tag>(`/pricelist/tags/${tag.id}`, tag);
      const index = this.tags.findIndex((a) => a.id === data.id);
      if (index > -1) {
        this.tags[index] = data;
      }
    },
    async deleteTag(tag: FG.Tag) {
      await api.delete(`/pricelist/tags/${tag.id}`);
      const index = this.tags.findIndex((a) => a.id === tag.id);
      if (index > -1) {
        this.tags.splice(index, 1);
      }
    },
    async getPriceCalcColumn(userid: string) {
      const { data } = await api.get<Array<string>>(`pricelist/users/${userid}/pricecalc_columns`);
      this.pricecalc_columns = data;
    },
    async updatePriceCalcColumn(userid: string, data: Array<string>) {
      await api.put<Array<string>>(`pricelist/users/${userid}/pricecalc_columns`, data);
      this.pricecalc_columns = data;
    },
    async getPriceListView(userid: string) {
      const { data } = await api.get<{ value: boolean }>(`pricelist/users/${userid}/pricelist`);
      this.pricelist_view = data.value;
    },
    async updatePriceListView(userid: string, data: boolean) {
      await api.put<Array<string>>(`pricelist/users/${userid}/pricelist`, { value: data });
      this.pricelist_view = data;
    },
    async getPriceListColumnOrder(userid: string) {
      const { data } = await api.get<Array<Order>>(
        `pricelist/users/${userid}/pricecalc_columns_order`
      );
      this.pricelist_columns_order = data;
    },
    async updatePriceListColumnOrder(userid: string, data: Array<Order>) {
      await api.put<Array<string>>(`pricelist/users/${userid}/pricecalc_columns_order`, data);
      this.pricelist_columns_order = data;
    },
  },
  getters: {
    pricelist() {
      const retVal: Array<Pricelist> = [];
      this.drinks.forEach((drink) => {
        drink.volumes.forEach((volume) => {
          volume.prices.forEach((price) => {
            retVal.push({
              name: drink.name,
              type: <FG.DrinkType>drink.type,
              tags: <Array<FG.Tag>>drink.tags,
              volume: <number>volume.volume,
              price: price.price,
              public: price.public,
              description: <string>price.description,
            });
          });
        });
      });
      return retVal;
    },
  },
});

export { DrinkPriceVolume, Drink, Order };