import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { map, tap } from 'rxjs';

import { FoodCardProps } from 'src/app/shared/interfaces/components/cards/food-card/food-card.interface';
import { Ingredient } from 'src/app/shared/interfaces/services/api-fit/response/ingredient.interface';
import {
  Meal,
  MealTime,
} from 'src/app/shared/interfaces/services/api-fit/response/meal.interface';
import { Recipe } from 'src/app/shared/interfaces/services/api-fit/response/recipe.interface';
import { CreateMeal } from 'src/app/shared/interfaces/services/api-fit/request/meal.interface';

import { ApiFitService } from 'src/app/shared/services/api-fit/api-fit.service';
import { ToastDispatchers } from 'src/app/core/stores/index.dispatchers';

@Component({
  selector: 'app-create',
  templateUrl: './create.component.html',
  styleUrls: ['./create.component.scss'],
})
export class CreateComponent {
  meal: CreateMeal = {
    date: new Date().toISOString(),
    mealTimeId: 0,
    foods: [],
    recipes: [],
  };
  mealTime = '';

  mealFoods: {
    card: FoodCardProps;
    ingredient: Ingredient;
  }[] = [];

  mealRecipes: {
    card: FoodCardProps;
    ingredients: Ingredient[];
  }[] = [];

  ingredients: Ingredient[] = [];

  foodToEdit: FoodCardProps | null = null;
  foodToRemove: FoodCardProps | null = null;

  isModalAddFoodOpen = false;
  searchType: 'food' | 'recipe' = 'food';

  maxFoods = 48;
  maxRecipes = 16;

  constructor(
    private activatedRoute: ActivatedRoute,
    private router: Router,
    private ApiFitService: ApiFitService,
    private toastDispatchers: ToastDispatchers,
  ) {}

  async ngOnInit() {
    try {
      this.setMealTime();
    } catch (err) {
      this.router.navigate(['/app/meals']);
    }
  }

  ngOnDestroy() {
    this.saveMeal();
  }

  async setMealTime() {
    try {
      const mealTimeName = await this.getMealTimeNameFromUrl();
      const mealTimes = await this.getMealTimes();

      const mealTime = mealTimes.find(
        (m) =>
          m.name.replaceAll(/ /g, '-').toLowerCase() ===
          mealTimeName.toLowerCase(),
      );

      if (!mealTime) throw new Error();

      this.mealTime = mealTime.name;
      this.meal.mealTimeId = mealTime.id;
    } catch (err) {
      this.router.navigate(['/app/meals']);
    }
  }

  getMealTimeNameFromUrl() {
    return new Promise(
      (
        resolve: (mealTimeName: string) => void,
        reject: (err: unknown) => void,
      ) => {
        this.activatedRoute.params.subscribe({
          next: (p) => {
            resolve(p['mealTime']);
          },
          error: reject,
        });
      },
    );
  }

  getMealTimes() {
    return new Promise(
      (
        resolve: (mealTimeList: MealTime[]) => void,
        reject: (err: unknown) => void,
      ) => {
        this.ApiFitService.getMealTimes().subscribe({
          next: (res) => resolve(res.data),
          error: reject,
        });
      },
    );
  }

  fetchMealById(id: Meal['id']) {
    return new Promise(
      (resolve: (meal: Meal) => void, reject: (err: unknown) => void) => {
        this.ApiFitService.getMealById(id).subscribe({
          next: (r) => resolve(r.data),
          error: reject,
        });
      },
    );
  }

  addRecipeData(recipe: Meal['recipes'][0]) {
    return this.ApiFitService.getRecipeIngredients({
      recipeId: recipe.id,
    }).pipe(
      map((response) => {
        return response.data.map((ingredient) => {
          return {
            ...ingredient,
            quantity:
              (ingredient.quantity / recipe.servings) * recipe.consumedServings,
          };
        });
      }),

      tap({
        next: (ingredients) => {
          this.mealRecipes = [
            ...this.mealRecipes,
            {
              card: {
                ...recipe,
                kcal: recipe.consumedKcal,
                quantity: recipe.consumedServings,
                type: 'recipe',
              },
              ingredients,
            },
          ];
        },
      }),
    );
  }

  addFoodData(food: Meal['foods'][0]) {
    return this.ApiFitService.getFoodById(food.id).pipe(
      map((response) => {
        return {
          ...response.data,
          quantity: food.quantity,
        } as Ingredient;
      }),

      tap({
        next: (ingredient) => {
          this.mealFoods = [
            ...this.mealFoods,
            {
              card: {
                ...ingredient,
                kcal: food.kcal,
                type: 'food',
              },
              ingredient,
            },
          ];
        },
      }),
    );
  }

  updateIngredientsList() {
    this.ingredients = [
      ...this.mealFoods.map((f) => f.ingredient),
      ...this.mealRecipes.map((r) => r.ingredients).flat(),
    ];
  }

  editFood(foodToEdit: FoodCardProps) {
    this.foodToEdit = Object.create(foodToEdit);
  }

  updateFood(editedFood: FoodCardProps | null) {
    const foodIndex = this.mealFoods.findIndex(
      (f) => f.card.id === editedFood?.id,
    );

    if (!editedFood || foodIndex === -1) return;

    const food = this.mealFoods[foodIndex];

    food.ingredient.quantity = editedFood.quantity;

    food.card = {
      ...food.card,
      ...editedFood,
    };

    this.updateIngredientsList();
    this.foodToEdit = null;
  }

  updateRecipe(editedRecipe: FoodCardProps | null) {
    const recipeIndex = this.mealRecipes.findIndex(
      (r) => r.card.id === editedRecipe?.id,
    );

    if (!editedRecipe || recipeIndex === -1) return;

    const recipe = this.mealRecipes[recipeIndex];

    recipe.ingredients = recipe.ingredients.map((i) => {
      return {
        ...i,
        quantity: (editedRecipe.quantity * i.quantity) / recipe.card.quantity,
      };
    });

    recipe.card = {
      ...recipe.card,
      ...editedRecipe,
    };

    this.updateIngredientsList();
  }

  excludeItem() {
    const id = this.foodToRemove?.id;

    if (!this.foodToRemove) return;

    if (this.foodToRemove.type === 'food') {
      this.mealFoods = this.mealFoods.filter((r) => r.card.id !== id);
    } else {
      this.mealRecipes = this.mealRecipes.filter((r) => r.card.id !== id);
    }

    this.foodToRemove = null;
    this.updateIngredientsList();
  }

  toggleAddFoodModal(type: 'food' | 'recipe') {
    if (type === 'food' && this.mealFoods.length >= this.maxFoods) return;
    if (type === 'recipe' && this.mealRecipes.length >= this.maxRecipes) return;

    this.isModalAddFoodOpen = !this.isModalAddFoodOpen;
    this.searchType = type;
  }

  addFood(food: FoodCardProps) {
    if (food.type === 'food') {
      this.meal.foods.push({
        id: food.id,
        quantity: food.quantity,
      });

      this.addFoodData(food).subscribe({
        next: () => this.updateIngredientsList(),
      });
    } else {
      const recipe = Object.create(food) as Recipe;

      this.meal.recipes.push({
        id: food.id,
        consumedServings: food.quantity,
      });

      this.addRecipeData({
        id: food.id,
        consumedKcal: food.kcal,
        consumedServings: food.quantity,
        name: food.name,
        servings: recipe.servings,
      }).subscribe({
        next: () => this.updateIngredientsList(),
      });
    }
  }

  saveMeal() {
    if (!this.meal.foods?.length && !this.meal.recipes?.length) return;

    this.ApiFitService.createMeal(this.meal).subscribe({
      next: () => {
        this.toastDispatchers.showSuccess({
          message: 'Refeição salva com sucesso!',
          delay: 3000,
          isVisible: true,
          shouldHideAutomatically: true,
          showCloseButton: true,
        });
      },
      error: () => {
        this.toastDispatchers.showError({
          message: 'Erro ao salvar refeição!',
          delay: 3000,
          isVisible: true,
          shouldHideAutomatically: true,
          showCloseButton: true,
        });
      },
    });
  }
}
