import { api } from 'src/boot/axios';
import { defineStore } from 'pinia';
import { AxiosResponse } from 'axios';
import { computed, ComputedRef, WritableComputedRef } from 'vue';

interface MinPrice extends Omit<FG.MinPrices, 'price'> {
  price?: WritableComputedRef<number>;
}

interface DrinkPriceVolume extends Omit<Omit<FG.DrinkPriceVolume, 'volume'>, 'min_prices'> {
  _volume: number;
  volume?: WritableComputedRef<number>;
  min_prices: MinPrice[];
}

interface Drink extends Omit<Omit<FG.Drink, 'cost_price_pro_volume'>, 'volumes'> {
  volumes: DrinkPriceVolume[];
  cost_price_pro_volume: WritableComputedRef<number | undefined>;
  _cost_price_pro_volume?: number;
}

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 = computed<number>({
      get: () => {
        if (this.ingredients.some((ingredient) => !!ingredient.drink_ingredient)) {
          let retVal = 0;
          this.ingredients.forEach((ingredient) => {
            if (ingredient.drink_ingredient?.volume) {
              retVal += ingredient.drink_ingredient.volume;
            }
          });
          this._volume = retVal;
          return retVal;
        } else {
          return this._volume;
        }
      },
      set: (val) => (this._volume = val),
    });
  }
}

class Drink {
  constructor({
    id,
    article_id,
    package_size,
    name,
    volume,
    cost_price_pro_volume,
    cost_price_package_netto,
    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_price_package_netto = cost_price_package_netto;
    this._cost_price_pro_volume = cost_price_pro_volume;
    this.cost_price_pro_volume = computed({
      get: () => {
        if (!!this.volume && !!this.package_size && !!this.cost_price_package_netto) {
          const retVal =
            ((this.cost_price_package_netto || 0) /
              ((this.volume || 0) * (this.package_size || 0))) *
            1.19;
          this._cost_price_pro_volume = Math.round(retVal * 1000) / 1000;
        }

        return this._cost_price_pro_volume;
      },
      set: (val) => (this._cost_price_pro_volume = val),
    });
    this.tags = tags;
    this.type = type;
    this.volumes = [];
    this.uuid = uuid;
    this.receipt = receipt;
  }
}

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

  state: () => ({
    drinkTypes: [] as Array<FG.DrinkType>,
    drinks: [] as Array<Drink>,
    extraIngredients: [] as Array<FG.ExtraIngredient>,
    pricecalc_columns: [] as Array<string>,
    min_prices: [] as Array<number>,
  }),

  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() {
      const { data } = await api.get<Array<FG.Drink>>('pricelist/drinks');
      this.drinks = [];
      data.forEach((drink) => {
        const _drink = new Drink(drink);
        drink.volumes.forEach((volume) => {
          const _volume = new DrinkPriceVolume(volume);
          _drink.volumes.push(_volume);
        });
        this.drinks.push(_drink);
      });
      this.create_min_prices();
      console.log(this.drinks);
    },
    sortPrices(volume: DrinkPriceVolume) {
      volume.prices.sort((a, b) => {
        if (a.price > b.price) return 1;
        if (b.price > a.price) return -1;
        return 0;
      });
    },
    deletePrice(price: FG.DrinkPrice, volume: FG.DrinkPriceVolume) {
      api
        .delete(`pricelist/prices/${price.id}`)
        .then(() => {
          const index = volume.prices.findIndex((a) => a.id == price.id);
          if (index > -1) {
            volume.prices.splice(index, 1);
          }
        })
        .catch((err) => console.warn(err));
    },
    deleteVolume(volume: FG.DrinkPriceVolume, drink: FG.Drink) {
      api
        .delete(`pricelist/volumes/${volume.id}`)
        .then(() => {
          const index = drink.volumes.findIndex((a) => a.id === volume.id);
          if (index > -1) {
            drink.volumes.splice(index, 1);
          }
        })
        .catch((err) => console.warn(err));
    },
    deleteIngredient(ingredient: FG.Ingredient, volume: DrinkPriceVolume) {
      api
        .delete(`pricelist/ingredients/${ingredient.id}`)
        .then(() => {
          const index = volume.ingredients.findIndex((a) => a.id === ingredient.id);
          if (index > -1) {
            volume.ingredients.splice(index, 1);
          }
        })
        .catch((err) => console.warn(err));
    },
    async setDrink(drink: FG.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);
      this.create_min_prices();
    },
    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;
      }
      this.create_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));
    },
    getPriceCalcColumn(userid: string) {
      api
        .get(`pricelist/users/${userid}/pricecalc_columns`)
        .then(({ data }: AxiosResponse<Array<string>>) => {
          if (data.length > 0) {
            this.pricecalc_columns = data;
          }
        })
        .catch((err) => console.log(err));
    },
    updatePriceCalcColumn(userid: string, data: Array<string>) {
      api
        .put(`pricelist/users/${userid}/pricecalc_columns`, data)
        .then(() => {
          this.pricecalc_columns = data;
        })
        .catch((err) => console.log(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);
      this.create_min_prices();
    },
    create_min_prices() {
      this.drinks.forEach((drink) => {
        drink.volumes.forEach((volume) => {
          volume.min_prices = [];
          this.min_prices.forEach((min_price) => {
            let computedMinPrice: ComputedRef;
            if (drink.cost_price_pro_volume) {
              computedMinPrice = computed<number>(
                () =>
                  (<number>(<unknown>drink.cost_price_pro_volume) *
                    <number>(<unknown>volume.volume) *
                    min_price) /
                  100
              );
            } else {
              computedMinPrice = computed<number>(() => {
                let retVal = 0;
                let extraIngredientPrice = 0;
                volume.ingredients.forEach((ingredient) => {
                  if (ingredient.drink_ingredient) {
                    const _drink = usePricelistStore().drinks.find(
                      (a) => a.id === ingredient.drink_ingredient?.drink_ingredient_id
                    );
                    retVal +=
                      ingredient.drink_ingredient.volume *
                      <number>(<unknown>_drink?.cost_price_pro_volume);
                  }
                  if (ingredient.extra_ingredient) {
                    extraIngredientPrice += ingredient.extra_ingredient.price;
                  }
                });
                return (retVal * min_price) / 100 + extraIngredientPrice;
              });
            }
            volume.min_prices.push({ percentage: min_price, price: computedMinPrice });
          });
        });
      });
    },
    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',
        },
      });
      drink.uuid = data.uuid;
    },
    async delete_drink_picture(drink: Drink) {
      await api.delete(`pricelist/drinks/${drink.id}/picture`);
      drink.uuid = '';
    },
  },
});

export { DrinkPriceVolume, MinPrice, Drink };