from typing import List, Optional, Union, Dict, Any
from sqlalchemy.orm import Session
import logging
import os
import uuid
from fastapi import HTTPException, UploadFile
from app.models.product import Product
from app.schemas.product import ProductResponse, ProductDetailResponse, ProductCreate
from app.models.product_image import ProductImage
from app.models.product_category import ProductCategory
from pydantic import BaseModel

from app.schemas.product_category import ProductCategoryBase
from app.services.media_service import MediaService

logger = logging.getLogger('adimsayar')

class UpdateProductImagesRequest(BaseModel):
    images: List[str]

class ProductService:
    @staticmethod
    def _process_product_specifications(specifications: Optional[Dict[str, Any]]) -> Dict[str, Any]:
        """Helper method to validate and process product specifications including sizes"""
        if not specifications:
            return {}
            
        processed_specs = dict(specifications)
        
        # Process sizes if present
        if "sizes" in processed_specs:
            # Ensure sizes is a list
            if not isinstance(processed_specs["sizes"], list):
                if isinstance(processed_specs["sizes"], str):
                    # If it's a comma-separated string, split it
                    processed_specs["sizes"] = [size.strip() for size in processed_specs["sizes"].split(',')]
                else:
                    # Default to empty list if invalid format
                    processed_specs["sizes"] = []
                    
        return processed_specs

    @staticmethod
    def get_products(db: Session) -> List[ProductResponse]:
        products = db.query(Product).all()
        logger.info(f"get_products: found {len(products)} products")
        return [ProductResponse.from_orm(product) for product in products]

    @staticmethod
    def get_product_detail(db: Session, product_id: int) -> ProductDetailResponse:
        product = db.query(Product).filter(Product.id == product_id).first()
        if not product:
            raise HTTPException(status_code=404, detail="Product not found")
        
        # Extract sizes from specifications if available
        sizes = []
        if product.specifications and "sizes" in product.specifications:
            sizes = product.specifications["sizes"]
        
        detail = {
            "id": product.id,
            "name": product.name,
            "description": product.description,
            "price": product.points_required,
            "images": [image.image_url for image in product.images] if product.images else [],
            "status": product.status,
            "inStock": product.stock > 0,
            "stockCount": product.stock,
            "sizes": sizes,
            "specifications": product.specifications,
            "created_at": product.created_at,
            "updated_at": product.updated_at,
        }
        return ProductDetailResponse(**detail)

    @staticmethod
    def update_product_images(db: Session, product_id: int, image_urls: List[str]) -> dict:
        product = db.query(Product).filter(Product.id == product_id).first()
        if not product:
            raise HTTPException(status_code=404, detail="Product not found")
        
        # 기존 이미지 초기화
        product.images.clear()
        
        # 새 이미지 데이터 추가 (정렬 순서는 인덱스를 사용)
        for idx, url in enumerate(image_urls):
            new_img = ProductImage(product_id=product_id, image_url=url, sort_order=idx)
            product.images.append(new_img)
        
        db.commit()
        return {"message": "Product images updated successfully."}

    @staticmethod
    def create_product(
        db: Session,
        product_in: ProductCreate,
        images: Optional[List[UploadFile]] = None,
        media_service: Optional[MediaService] = None,
    ) -> Product:
        # 1. 카테고리 매핑: category_id 필드가 실제 정수 id인지, 아니면 카테고리 코드(문자열)인지 확인
        try:
            # 우선 정수로 변환 시도
            category_id = int(product_in.category_id)
            category_obj = db.query(ProductCategory).filter(ProductCategory.id == category_id).first()
            if not category_obj:
                raise HTTPException(status_code=400, detail="Invalid category ID")
        except ValueError:
            # 변환 실패 → 카테고리 코드로 처리
            category_obj = db.query(ProductCategory).filter(ProductCategory.code == product_in.category_id).first()
            if not category_obj:
                 raise HTTPException(status_code=400, detail="Invalid category code")
            category_id = category_obj.id

        # 2. 상품 데이터 생성: 전달받은 payload에 매핑된 category id를 반영
        product_data = product_in.dict()
        product_data["category_id"] = category_id
        
        # Process specifications including sizes
        if product_data.get("specifications"):
            product_data["specifications"] = ProductService._process_product_specifications(product_data["specifications"])
            
        product = Product(**product_data)
        db.add(product)
        db.commit()
        db.refresh(product)

        # 3. 이미지 업로드 처리 (옵셔널, 최대 5개)
        if images:
            try:
                if len(images) > 5:
                    raise HTTPException(status_code=400, detail="Maximum 5 images allowed")
                
                logger.info(f"Starting image upload process for product ID: {product.id}, category: {category_obj.code}")
                
                if not media_service:
                    logger.error("MediaService not provided for image upload")
                    raise ValueError("MediaService not provided for image upload")
                
                logger.info(f"Media service instance: {media_service}")
                logger.info(f"Got {len(images)} images to upload")
                
                for idx, upload_file in enumerate(images):
                    if not upload_file or not upload_file.filename:
                        logger.warning(f"Empty or invalid file at index {idx}, skipping")
                        continue
                        
                    logger.info(f"Processing image {idx+1}/{len(images)} with filename: {upload_file.filename}")
                    folder_path = f"product/{category_obj.code}/{product.id}"
                    logger.info(f"Using folder path: {folder_path}")
                    
                    try:
                        logger.info(f"Calling media_service.upload_image with folder={folder_path}")
                        image_url = media_service.upload_image(upload_file, folder=folder_path)
                        logger.info(f"Successfully uploaded image to {image_url}")
                        
                        new_img = ProductImage(product_id=product.id, image_url=image_url, sort_order=idx)
                        db.add(new_img)
                        logger.info(f"Added image record to database with URL: {image_url}")
                    except Exception as img_err:
                        logger.error(f"Failed to upload image {upload_file.filename}: {str(img_err)}", exc_info=True)
                        # 이미지 업로드 실패 시에도 계속 진행 (다른 이미지는 처리)
                
                # 모든 이미지 업로드 후 커밋
                db.commit()
                logger.info(f"Completed image upload process for product ID: {product.id}")
            except Exception as e:
                logger.error(f"Error during image upload process: {str(e)}", exc_info=True)                
        return product

    @staticmethod
    def create_product_category(db: Session, category_in: ProductCategoryBase) -> ProductCategory:
        # Move the category creation logic from the endpoint here.
        existing_category = db.query(ProductCategory).filter(ProductCategory.code == category_in.code).first()
        if existing_category:
            raise HTTPException(status_code=400, detail="Category already exists")
        new_category = ProductCategory(**category_in.dict())
        db.add(new_category)
        db.commit()
        db.refresh(new_category)
        return new_category

    @staticmethod
    def delete_product(db: Session, product_id: int) -> dict:
        product = db.query(Product).filter(Product.id == product_id).first()
        if not product:
            raise HTTPException(status_code=404, detail="Product not found")
        
        # 상품의 모든 이미지를 삭제
        for image in product.images:
            db.delete(image)
        
        db.commit()  # 이미지 삭제 커밋
        
        # 상품 삭제
        db.delete(product)
        db.commit()  # 상품 삭제 커밋
        
        return {"message": "Product deleted successfully."}

    @staticmethod
    def update_product(
        db: Session,
        product_id: int,
        product_in: ProductCreate,
        images: Optional[List[UploadFile]] = None,
        media_service: Optional[MediaService] = None,
    ) -> Product:
        # 기존 상품 조회
        product = db.query(Product).filter(Product.id == product_id).first()
        if not product:
            raise HTTPException(status_code=404, detail="Product not found")

        # 1. 카테고리 매핑: category_id 필드가 실제 정수 id인지, 아니면 카테고리 코드(문자열)인지 확인
        try:
            # 우선 정수로 변환 시도
            category_id = int(product_in.category_id)
            category_obj = db.query(ProductCategory).filter(ProductCategory.id == category_id).first()
            if not category_obj:
                raise HTTPException(status_code=400, detail="Invalid category ID")
        except ValueError:
            # 변환 실패 → 카테고리 코드로 처리
            category_obj = db.query(ProductCategory).filter(ProductCategory.code == product_in.category_id).first()
            if not category_obj:
                 raise HTTPException(status_code=400, detail="Invalid category code")
            category_id = category_obj.id

        # 2. 상품 데이터 업데이트
        product_data = product_in.dict(exclude_unset=True)
        product_data["category_id"] = category_id
        
        # Process specifications including sizes
        if "specifications" in product_data and product_data["specifications"]:
            product_data["specifications"] = ProductService._process_product_specifications(product_data["specifications"])
        
        for key, value in product_data.items():
            setattr(product, key, value)

        # 3. 이미지 업로드 처리 (옵셔널, 최대 5개)
        if images:
            try:
                if len(images) > 5:
                    raise HTTPException(status_code=400, detail="Maximum 5 images allowed")
                
                logger.info(f"Starting image upload process for product ID: {product.id}, category: {category_obj.code}")
                
                if not media_service:
                    logger.error("MediaService not provided for image upload")
                    raise ValueError("MediaService not provided for image upload")
                
                # 기존 이미지 삭제
                product.images.clear()
                
                for idx, upload_file in enumerate(images):
                    if not upload_file or not upload_file.filename:
                        logger.warning(f"Empty or invalid file at index {idx}, skipping")
                        continue
                        
                    logger.info(f"Processing image {idx+1}/{len(images)} with filename: {upload_file.filename}")
                    folder_path = f"product/{category_obj.code}/{product.id}"
                    
                    try:
                        logger.info(f"Calling media_service.upload_image with folder={folder_path}")
                        image_url = media_service.upload_image(upload_file, folder=folder_path)
                        logger.info(f"Successfully uploaded image to {image_url}")
                        
                        new_img = ProductImage(product_id=product.id, image_url=image_url, sort_order=idx)
                        db.add(new_img)
                        logger.info(f"Added image record to database with URL: {image_url}")
                    except Exception as img_err:
                        logger.error(f"Failed to upload image {upload_file.filename}: {str(img_err)}", exc_info=True)
                        # 이미지 업로드 실패 시에도 계속 진행 (다른 이미지는 처리)
                
                logger.info(f"Completed image upload process for product ID: {product.id}")
            except Exception as e:
                logger.error(f"Error during image upload process: {str(e)}", exc_info=True)
                # 이미지 업로드 실패가 상품 업데이트 자체를 실패시키지 않도록 함

        db.commit()
        db.refresh(product)
        return product