from celery import shared_task
from utils.celery.celery_base_task import *
import logging, gdown, pandas as pd, json, os, re, requests, shutil
from archives.models import Archives
from .models import Products, Categories, Series, ProductGallery, NewArrivalProducts
from django.core.cache import cache
from utils.r2.client import R2
from pathlib import Path

logging.basicConfig(
    level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)

BASE_DIR = Path(__file__).resolve().parent
BASE_IMAGE_DIRECTORY = f"{BASE_DIR}/caracole_images"


def validate_value_if_nan(value, is_digit=False):  # pragma: no cover
    if pd.isna(value) or value == "":
        if is_digit:
            return 0

        return None

    return value


def download_and_upload_image_to_r2(
    edp_number, image_path, is_main=True, lifestyle_counter=0
):
    def build_file_name():
        suffix = "main" if is_main else f"lifestyle_{lifestyle_counter}"
        return f"{edp_number}_{suffix}.jpg"

    def gdrive(file_directory, complete_gdrive_link, file_name):
        if not os.path.isdir(file_directory):
            os.makedirs(file_directory)

        output_path = os.path.join(file_directory, file_name)
        gdown.download(
            complete_gdrive_link, output=output_path, quiet=False, use_cookies=False
        )
        file_path = f"{file_directory}/{file_name}"
        return file_path

    def cdn(file_directory, file_name):
        if not os.path.isdir(file_directory):
            os.makedirs(file_directory)

        file_path = f"{file_directory}/{file_name}"
        with open(file_path, "wb") as file:
            file.write(response.content)

        return file_path

    if not os.path.isdir(BASE_IMAGE_DIRECTORY):
        os.makedirs(BASE_IMAGE_DIRECTORY)

    gdrive_link_match = re.search(r"d/([^/]+)/view", image_path)
    file_name = build_file_name()
    file_directory = f"{BASE_DIR}/caracole_images/{edp_number}"

    if gdrive_link_match:
        link_id = gdrive_link_match.group(1)
        complete_drive_link = f"https://drive.google.com/uc?id={link_id}"

        file_path = gdrive(
            file_directory=file_directory,
            complete_gdrive_link=complete_drive_link,
            file_name=file_name,
        )
    else:
        response = requests.get(image_path)

        if response.status_code != 200:
            return False

        file_path = cdn(file_directory=file_directory, file_name=file_name)

    r2 = R2(file=file_path, main_folder_name="products")
    r2.upload_fileobj(sub_folder_path=f"{edp_number}/")
    cdn_link = f"https://cdn.caracole.ph/products/{edp_number}/{file_name}"
    return cdn_link


@shared_task
def upload_products(file_contents):  # pragma: no cover
    logging.info(f"Uploading {len(file_contents)} products...")
    cache.set("upload_status", "uploading", timeout=3600)

    errors = []

    new_arrival_products = NewArrivalProducts.objects.all()
    new_arrival_products_count = new_arrival_products.count()

    for product in new_arrival_products:
        product.delete()

    logging.info(
        f"Made new arrival status to False for {new_arrival_products_count} products."
    )

    for row in file_contents:
        name = row["Name"]
        edp_number = row["EDP Number"]
        article_number = validate_value_if_nan(value=row.get("Article Number"))
        description = validate_value_if_nan(value=row.get("Description"))
        finish = validate_value_if_nan(value=row.get("Finish"))
        size = validate_value_if_nan(value=row.get("Size"))
        category = row["Categories"]
        sub_category = row["Sub Category"]
        price = validate_value_if_nan(value=row.get("Price"), is_digit=True)
        series = validate_value_if_nan(value=row.get("Series"))
        quantity = validate_value_if_nan(value=row.get("Quantity"), is_digit=True)
        silo_image = validate_value_if_nan(value=row.get("SILO Image"))
        editorial_images = validate_value_if_nan(value=row.get("Editorial Images"))
        is_coming_soon = validate_value_if_nan(value=row.get("Is Coming Soon?"))
        is_new_arrival = validate_value_if_nan(value=row.get("Is New Arrival?"))

        if is_coming_soon and is_coming_soon.lower() == "yes":
            is_coming_soon = True
        else:
            is_coming_soon = False

        if is_new_arrival is not None and is_new_arrival.lower() == "yes":
            is_new_arrival = True
        else:
            is_new_arrival = False

        existing_series = None
        category_arr = category.split(",")
        category_arr_title = [c.title() for c in category_arr]

        existing_categories = Categories.objects.filter(
            main_category_name__contains=category_arr_title,
            sub_category_name=sub_category,
        )

        if not silo_image:
            logging.error(f"Main image for {name} is missing.")
            errors.append(f"Main image for {name} is missing.")
            break

        if description:
            # Convert to Quill format
            description = json.dumps({"delta": "", "html": f"<p>{description}</p>"})

        if not existing_categories.exists():
            logging.error(
                f"Categories '{category_arr}' and Sub-Category '{sub_category}' does not exist."
            )
            errors.append(
                f"Categories '{category_arr}' and Sub-Category '{sub_category}' does not exist."
            )
            break

        if series and series.strip() != "":
            existing_series = Series.objects.filter(name__iexact=series)

            if not existing_series.exists():
                logging.error(f"Series {series} does not exist.")
                errors.append(f"Series {series} does not exist.")
                break

            existing_series = existing_series.first()

        category_obj = existing_categories.first()

        silo_image_cdn = download_and_upload_image_to_r2(
            edp_number=edp_number, image_path=silo_image
        )

        if silo_image_cdn is False:
            errors.append(
                f"Error uploading main image of {edp_number} using image path: '{silo_image}'"
            )

        try:
            product = Products.objects.get(edp_number=edp_number)
            product.name = name
            if not product.article_number:
                product.article_number = article_number

            if not product.finish:
                product.finish = finish

            if not product.size:
                product.size = size

            product.description = description
            product.quantity = quantity
            product.category = category_obj
            product.series = existing_series
            product.price = price
            product.image_path = silo_image_cdn
            product.is_coming_soon = is_coming_soon
            product.is_new_arrival = is_new_arrival
            product.save()

            logging.info(f"Updated product: {product.name}")
        except Products.DoesNotExist:
            product = Products.objects.create(
                name=name,
                edp_number=edp_number,
                article_number=article_number,
                finish=finish,
                size=size,
                category=category_obj,
                series=existing_series,
                price=price,
                description=description,
                quantity=quantity,
                image_path=silo_image_cdn,
                is_coming_soon=is_coming_soon,
                is_new_arrival=True,
            )

            logging.info(f"Created product: {product.name}")

        if editorial_images:
            editorial_images_arr = editorial_images.split("\n")
            logging.info(
                f"Creating {len(editorial_images_arr)} product images for {product.name}."
            )

            product_images_to_create = []

            for index, editorial_image in enumerate(editorial_images_arr):
                count = index + 1
                editorial_image = editorial_image.strip()

                image_cdn = download_and_upload_image_to_r2(
                    edp_number=edp_number,
                    image_path=editorial_image,
                    is_main=False,
                    lifestyle_counter=count,
                )

                product_images_to_create.append(
                    ProductGallery(image_path=image_cdn, product=product)
                )

            ProductGallery.objects.bulk_create(product_images_to_create)
            logging.info(
                f"Created {len(editorial_images_arr)} product images for {product.name}"
            )

    if errors:
        logging.info(f"Errors encountered during upload.")
        cache.set(
            "product_upload_error",
            errors,
            timeout=3600,
        )
        cache.set("upload_status", "error", timeout=3600)
    else:
        shutil.rmtree(BASE_IMAGE_DIRECTORY)
        logging.info(f"Finish uploading products.")
        cache.set("upload_status", "complete", timeout=3600)


@shared_task
def delete_archived_products():
    archived_products = Archives.objects.filter(model="Products").values_list(
        "id", flat=True
    )
    logging.error(f"Deleting {len(archived_products)} archived products...")

    Products.objects.filter(id__in=archived_products).delete()
    logging.info(f"Deleted {len(archived_products)} archived products")
