import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { forkJoin } from 'rxjs';

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

import { ApiFitService } from 'src/app/shared/services/api-fit/api-fit.service';

import { LoaderDispatchers, ToastDispatchers } from 'src/app/core/stores/index.dispatchers';
import { Toast } from 'src/app/core/interfaces/store/toast.interface';

@Component({
  selector: 'app-create',
  templateUrl: './create.component.html',
  styleUrls: ['./create.component.scss'],
})
export class EditComponent {
  recipe: NewRecipe = {
    name: '',
    servings: 1,
    ingredients: [],
    stepBySteps: [''],
    tagsIds: [],
  };
  recipePicture: File | null = null;

  selectedTags: RecipeTag[] = [];
  selectedIngredients: FoodCardProps[] = [];

  isModalAddIngredientOpen = false;
  isModalAddTagOpen = false;
  isModalNutritionalInformationsOpen = false;

  ingredientToEdit: FoodCardProps | null = null;

  recipeIngredientsInformations: Ingredient[] = [];

  validationList = {
    title: {
      regex: [/^[a-zà-ú- ]+$/i],
      message: 'O nome da receita deve conter apenas letras',
      hasError: false
    }
  };

  constructor(
    private apiFitService: ApiFitService,
    private toastDispatchers: ToastDispatchers,
    private router: Router,
    private loaderDispatcher: LoaderDispatchers
  ) {
  }

  setRecipeStep(index: number, value: string) {
    const newValue = value.trim();

    if (!newValue) {
      if (index === this.recipe.stepBySteps.length - 1) return;

      this.recipe.stepBySteps.splice(index, 1);
      return;
    }

    this.recipe.stepBySteps[index] = newValue;

    if (index === this.recipe.stepBySteps.length - 1) {
      setTimeout(() => {
        this.recipe.stepBySteps = [...new Set(this.recipe.stepBySteps.filter(s => s.trim()))];
        setTimeout(() => {
          this.recipe.stepBySteps.push('');
        }, 500);
      }, 250);
    }
  }

  openModalAddTag() {
    this.isModalAddTagOpen = true;
  }

  openModalAddIngredient() {
    this.isModalAddIngredientOpen = true;
  }

  handleAddIngredient(ingredient: FoodCardProps) {
    const index = this.selectedIngredients.findIndex(
      (item) => item.id === ingredient.id,
    );

    if (index !== -1) {
      this.recipe.ingredients.splice(index, 1);
      this.selectedIngredients.splice(index, 1);
    }

    const newIngredient = Object.create(ingredient) as FoodCardProps;

    this.selectedIngredients.push(newIngredient);
    this.recipe.ingredients.push({
      id: newIngredient.id,
      quantity: newIngredient.quantity,
    });

    this.ingredientToEdit = null;
  }

  handleEditIngredient(ingredient: FoodCardProps) {
    this.ingredientToEdit = ingredient;
    this.isModalAddIngredientOpen = true;
  }

  handleRemoveIngredient(ingredient: FoodCardProps) {
    const index = this.selectedIngredients.findIndex(
      (item) => item.id === ingredient.id,
    );

    if (index === -1) return;

    this.recipe.ingredients.splice(index, 1);
    this.selectedIngredients.splice(index, 1);
  }

  handleSelectedTags(tags: RecipeTag[]) {
    this.selectedTags = [...tags];
    this.recipe.tagsIds = tags.map((tag) => tag.id);
  }

  removeSelectedTag(tag: RecipeTag) {
    const index = this.selectedTags.findIndex((item) => item.id === tag.id);

    if (index === -1) return;

    this.selectedTags.splice(index, 1);
    this.recipe.tagsIds.splice(index, 1);
  }

  updateIngredient() {
    if (!this.ingredientToEdit) return;

    const index = this.selectedIngredients.findIndex(
      (item) => item.id === this.ingredientToEdit?.id,
    );

    if (index === -1) return;

    this.recipe.ingredients[index] = { ...this.ingredientToEdit };
    this.selectedIngredients[index] = { ...this.ingredientToEdit };

    this.ingredientToEdit = null;
    this.isModalAddIngredientOpen = false;
  }

  isModalNutritionalInformationsEnabled() {
    return this.recipe.ingredients.length > 0;
  }

  openModalNutritionalInformations() {
    this.isModalNutritionalInformationsOpen = true;

    const ingredientsRequests = this.recipe.ingredients.map((ingredient) => {
      return this.apiFitService.getFoodById(ingredient.id);
    });

    forkJoin(ingredientsRequests).subscribe({
      next: (res) => {
        const ingredientsInformations = res.map((r) => r.data);

        this.recipeIngredientsInformations = ingredientsInformations.map(
          (i) => {
            const quantity = this.recipe.ingredients.find(
              (ingredient) => ingredient.id === i.id,
            )?.quantity;

            return {
              ...i,
              quantity: quantity ?? 0,
            };
          },
        );
      },
    });
  }

  isRecipeValid() {
    const hasSomeValidationError = Object.values(this.validationList).some(val => val.hasError);

    return (
      this.recipe.name.trim() !== '' &&
      this.recipe.ingredients.length > 0 &&
      this.recipe.stepBySteps.filter((s) => s.trim()).length > 0 &&
      this.recipe.servings > 0 &&
      !hasSomeValidationError
    );
  }

  saveRecipePicture(recipeId: number) {
    return new Promise(
      (resolve: (data: unknown) => void, reject: (reason: unknown) => void) => {
        if (!this.recipePicture) {
          resolve(null);
          return;
        }

        this.apiFitService
          .saveRecipePicture({
            picture: this.recipePicture,
            recipeId: recipeId,
          })
          .subscribe({
            next: resolve,
            error: reject,
          });
      },
    );
  }

  saveRecipe() {
    return new Promise(
      (resolve: (data: Recipe) => void, reject: (reason: unknown) => void) => {
        this.apiFitService
          .createRecipe({
            ...this.recipe,
            stepBySteps: [...new Set(this.recipe.stepBySteps.filter((s) => s.trim()))],
          })
          .subscribe({
            next: (res) => resolve(res.data),
            error: reject,
          });
      },
    );
  }

  createRecipe() {
    this.loaderDispatcher.showLoader();

    this.saveRecipe()
      .then((recipe) => {
        this.loaderDispatcher.showLoader();
        
        this.saveRecipePicture(recipe.id)
          .then(() => {
            this.toastDispatchers.showSuccess({
              isVisible: true,
              message: 'Receita criada com sucesso!',
            } as Toast);

            this.redirectToCreatedRecipe(recipe);
          })
          .catch(() => {
            this.toastDispatchers.showError({
              isVisible: true,
              message: 'Ocorreu um erro ao salvar a imagem da receita!',
            } as Toast);

            this.redirectToCreatedRecipe(recipe);
          });
      })
      .catch(() => {
        this.toastDispatchers.showError({
          isVisible: true,
          message: 'Erro ao salvar receita!',
        } as Toast);

        this.loaderDispatcher.hideLoader();
      });
  }

  redirectToCreatedRecipe(recipe: Recipe) {
    const { name, id } = recipe;
    const nameWithoutSpaces = name.replace(/\s/g, '-');

    setTimeout(() => {
      this.loaderDispatcher.hideLoader();
      this.router.navigate(['/app/foods/', `${nameWithoutSpaces}-${id}`]);
    }, 1025);
  }
}
