import { NextResponse } from "next/server";

import { getServerSession } from "next-auth";

import prismadb from "@/lib/prisma";

function strNoAccentNoSlash(a: string) {
  //enlever les accents
  let withoutAccents = a.normalize('NFD').replace(/[\u0300-\u036f]/g, '');

  //remplacer les '/' par '-'
  return withoutAccents.replace(/\//g, '-');
}

export async function POST(
  req: Request,
  { params }: { params: { storeId: string } }
) {
  try {
    const session = await getServerSession();
    const userId = session?.user?.email;

    const body = await req.json();

    const {
      name,
      reference,
      itemCode,
      shortDescription,
      description,
      price,
      purchasePrice,
      categoryId,
      brandId,
      featureValueToProduct,
      weight,
      carrierSurplus,
      stock,
      showMsgTwoLastStock,
      msgOutOfStock,
      showOutOfStock,
      orderOutOfStock,
      images,
      promotion,
      isFeatured,
      isArchived
    } = body;

    let brand = brandId;
    let slug = "";

    if (!userId) {
      return new NextResponse("Non connecté", { status: 401 });
    }

    if (!name) {
      return new NextResponse("Nom requis", { status: 400 });
    }

    if (!shortDescription) {
      return new NextResponse("Brève description requise", { status: 400 });
    }

    if (!description) {
      return new NextResponse("Description requise", { status: 400 });
    }

    if (!images || !images.length) {
      return new NextResponse("Images requises", { status: 400 });
    }

    if (!price) {
      return new NextResponse("Prix requis", { status: 400 });
    }

    if (!purchasePrice) {
      return new NextResponse("Prix d'achat requis", { status: 400 });
    }

    if (!categoryId) {
      return new NextResponse("Catégorie requise", { status: 400 });
    }

    if (!weight && weight !== 0) {
      return new NextResponse("Poids requis", { status: 400 });
    }

    if (!stock && stock !== 0) {
      return new NextResponse("Stock requis", { status: 400 });
    }

    if (!msgOutOfStock) {
      return new NextResponse("Message hors stock requis", { status: 400 });
    }

    if (!params.storeId) {
      return new NextResponse("Id de boutique requise", { status: 400 });
    }

    if (brandId == undefined || brandId == '') {
      brand = null;
    }

    const storeByUserId = await prismadb.store.findFirst({
      where: {
        id: params.storeId,
      },
      include: {
        userToStore: {
          where: {
            userId: userId
          }
        }
      }
    });

    if (!storeByUserId) {
      return new NextResponse("Non autorisé", { status: 403 });
    }

    //création du slug
    const productExist = await prismadb.product.findFirst({
      where: {
        name,
        categoryId
      }
    })

    if (productExist) {
      return new NextResponse("Ce produit existe déjà dans cette catégorie", { status: 400 });
    }
    else {
      const category = await prismadb.category.findFirst({
        where: {
          id: categoryId
        }
      })
      slug = category?.slug + "-" + strNoAccentNoSlash(name).toLowerCase().replace(/\s+/g, '-');
    }

    //on fait une liste des featureValues non undefined ou = à ''
    const filteredFeatureValues = featureValueToProduct
      .filter((feature: any) => feature.featureValue && feature.featureValue.value !== undefined && feature.featureValue.value.length > 0)
      .map((feature: any) => ({
        featureValueId: feature.featureValue.value,
      }));

    const product = await prismadb.product.create({
      data: {
        name,
        slug,
        reference,
        itemCode,
        shortDescription,
        description,
        price,
        purchasePrice,
        weight,
        carrierSurplus,
        stock,
        showMsgTwoLastStock,
        msgOutOfStock,
        showOutOfStock,
        orderOutOfStock,
        isFeatured,
        isArchived,
        categoryId,
        brandId: brand,
        storeId: params.storeId,
        images: {
          createMany: {
            data: [
              ...images.map((image: { url: string, order: number }) => image)
            ]
          }
        },
        featureValueToProduct: {
          createMany: {
            data: filteredFeatureValues.map((featureId: any) => ({
              featureValueId: featureId.featureValueId
            }))
          }
        },
        ...(promotion.unit !== '' && {
          promotion: {
            create: {
              unit: promotion.unit,
              amount: promotion.amount,
              finishAt: promotion.finishAt
            }
          },
        }),
      }
    });

    return NextResponse.json(product);

  } catch (error) {
    console.log('[PRODUCTS_POST]', error);
    return new NextResponse("Internal error", { status: 500 })
  }
};


export async function GET(
  req: Request,
  { params }: { params: { storeId: string } }
) {
  try {
    const { searchParams } = new URL(req.url);
    const categorySlug = searchParams.get("categorySlug") || undefined;
    const isFeatured = searchParams.get("isFeatured");
    const featureValueIds = searchParams.getAll("caractId");
    const brandId = searchParams.get("brandId") || undefined;

    if (!params.storeId) {
      return new NextResponse("Store id is required", { status: 400 });
    }

    let productsWhere: any = {
      storeId: params.storeId,
      brandId,
      isFeatured: isFeatured ? true : undefined,
      isArchived: false,
      OR: []
    };

    if (!isFeatured) {
      //récup de l'id de la catégorie avec le slug
      const category = await prismadb.category.findFirst({
        where: {
          storeId: params.storeId,
          slug: categorySlug
        }
      });

      if (!category) {
        return new NextResponse("Category not found", { status: 404 });
      }

      const categoryIds = await getCategoryIds(params.storeId, category.id);

      //ajout des conditions pour les stocks et les catégories dans la même clause OR
      productsWhere.OR.push({
        OR: [
          { stock: { gt: 0 } },
          { AND: [{ stock: { lte: 0 } }, { showOutOfStock: true }] }
        ],
        categoryId: { in: categoryIds }
      });
    }
    else {
      productsWhere.OR.push({
        OR: [
          { stock: { gt: 0 } },
          { AND: [{ stock: { lte: 0 } }, { showOutOfStock: true }] }
        ]
      });
    }

    const products = await prismadb.product.findMany({
      where: productsWhere,
      include: {
        images: {
          orderBy: {
            order: 'asc'
          }
        },
        category: true,
        promotion: true,
        brand: true,
        featureValueToProduct: {
          include: {
            featureValue: {
              include: {
                feature: true
              }
            }
          }
        }
      },
      orderBy: {
        createdAt: "desc"
      }
    });

    //si featureValueIds n'est pas vide, filtrer les produits selon les caractéristiques sélectionnées
    if (featureValueIds.length > 0) {
      const filteredProducts = products.filter((product) => {
        const productFeatureValueIds = product.featureValueToProduct.map(
          (fvtp) => fvtp.featureValueId
        );
        return featureValueIds.every((id) =>
          productFeatureValueIds.includes(id)
        );
      });

      return NextResponse.json(filteredProducts);
    } else {
      return NextResponse.json(products);
    }
  } catch (error) {
    console.log("[PRODUCTS_GET]", error);
    return new NextResponse("Internal error", { status: 500 });
  }
}

// Fonction pour récupérer les IDs de toutes les sous-catégories récursivement
async function getCategoryIds(storeId: string, categoryId: string): Promise<string[]> {
  const childCategories = await prismadb.category.findMany({
    where: {
      storeId,
      parentCategoryId: categoryId
    },
    select: { id: true }
  });

  const categoryIds = childCategories.map((childCategory) => childCategory.id);
  categoryIds.push(categoryId);

  // Récupération des sous-catégories de manière récursive
  for (const childCategory of childCategories) {
    const subCategoryIds = await getCategoryIds(storeId, childCategory.id);
    categoryIds.push(...subCategoryIds);
  }

  return categoryIds;
}
