from rest_framework import serializers

from thirdparty.stripe.client import StripeClient

from .models import Refund, Order, Invoice, Review


class RefundCreatePublicSerializer(serializers.Serializer):
	email = serializers.EmailField()
	invoice_number = serializers.CharField(required=False, allow_blank=True)
	order_id = serializers.IntegerField(required=False)

	# Optional reason fields
	reason_choice = serializers.ChoiceField(
		choices=Refund.Reason.choices, required=False
	)
	reason_text = serializers.CharField(required=False, allow_blank=True)

	def validate(self, attrs):
		email = attrs.get("email")
		invoice_number = (attrs.get("invoice_number") or "").strip()
		order_id = attrs.get("order_id")

		if not invoice_number and not order_id:
			raise serializers.ValidationError(
				"Provide either invoice_number or order_id."
			)

		order = None
		if invoice_number:
			try:
				invoice = Invoice.objects.get(invoice_number=invoice_number)
				order = invoice.order
			except Invoice.DoesNotExist:
				raise serializers.ValidationError({"invoice_number": "Invoice not found."})
			except Order.DoesNotExist:
				raise serializers.ValidationError({"invoice_number": "Order for invoice not found."})

		if order_id and order is None:
			try:
				order = Order.objects.get(id=order_id)
			except Order.DoesNotExist:
				raise serializers.ValidationError({"order_id": "Order not found."})

		# Verify email matches order's email or user's email
		if not order:
			raise serializers.ValidationError("Order could not be resolved.")

		order_email = (order.email or "").strip().lower()
		user_email = (getattr(order.user, "email", "") or "").strip().lower()
		provided = email.strip().lower()
		if provided not in {order_email, user_email}:
			raise serializers.ValidationError({"email": "Email does not match the order."})

		attrs["order"] = order
		return attrs

	def create(self, validated_data):
		order = validated_data["order"]
		reason_choice = validated_data.get("reason_choice") or Refund.Reason.OTHER
		reason_text = validated_data.get("reason_text", "")

		refund = Refund.objects.create(
			order=order,
			reason_choice=reason_choice,
			reason_text=reason_text,
		)
		return refund

from rest_framework import serializers
from drf_spectacular.utils import extend_schema_field
from decimal import Decimal
from django.contrib.auth import get_user_model
from django.db import transaction
from django.core.exceptions import ValidationError


from .models import (
	Category,
	Product,
	ProductImage,
	DiscountCode,
	Refund,
	Order,
	OrderItem,
	Carrier,
	Payment,
	Cart,
	CartItem,
	Wishlist,
)

from thirdparty.stripe.models import StripeModel

from thirdparty.zasilkovna.serializers import ZasilkovnaPacketSerializer
from thirdparty.zasilkovna.models import ZasilkovnaPacket

User = get_user_model()

# ----------------- CREATING ORDER SERIALIZER -----------------

#correct
# -- CARRIER --
class OrderCarrierSerializer(serializers.ModelSerializer):
	# vstup: jen ID adresy z widgetu (write-only)
	packeta_address_id = serializers.IntegerField(required=False, write_only=True)

	# výstup: serializovaný packet
	zasilkovna = ZasilkovnaPacketSerializer(many=True, read_only=True)

	class Meta:
		model = Carrier
		fields = ["shipping_method", "state", "zasilkovna", "shipping_price", "packeta_address_id"]
		read_only_fields = ["state", "shipping_price", "zasilkovna"]

	def create(self, validated_data):
		packeta_address_id = validated_data.pop("packeta_address_id", None)

		carrier = Carrier.objects.create(**validated_data)

		if packeta_address_id is not None:
			# vytvoříme nový packet s danou addressId
			packet = ZasilkovnaPacket.objects.create(addressId=packeta_address_id)
			carrier.zasilkovna.add(packet)

		return carrier


#correct
# -- ORDER ITEMs --
class OrderItemCreateSerializer(serializers.Serializer):
	product_id = serializers.IntegerField()
	quantity = serializers.IntegerField(min_value=1, default=1)

	def validate(self, attrs):
		product_id = attrs.get("product_id")
		try:
			product = Product.objects.get(pk=product_id)
		except Product.DoesNotExist:
			raise serializers.ValidationError({"product_id": "Product not found."})
		
		attrs["product"] = product
		return attrs



# -- PAYMENT --
class PaymentSerializer(serializers.ModelSerializer):
	stripe_session_id = serializers.CharField(source='stripe.stripe_session_id', read_only=True)
	stripe_payment_intent = serializers.CharField(source='stripe.stripe_payment_intent', read_only=True)
	stripe_session_url = serializers.URLField(source='stripe.stripe_session_url', read_only=True)

	class Meta:
		model = Payment
		fields = [
			"id",
			"payment_method",
			"stripe",
			"stripe_session_id",
			"stripe_payment_intent",
			"stripe_session_url",
		]
		read_only_fields = [
			"id",
			"stripe",
			"stripe_session_id",
			"stripe_payment_intent",
			"stripe_session_url",
		]

	def create(self, validated_data):
		order = self.context.get("order")  # musíš ho předat při inicializaci serializeru
		carrier = self.context.get("carrier")

		with transaction.atomic():
			payment = Payment.objects.create(
				order=order,
				carrier=carrier,
				**validated_data
			)

			# pokud je Stripe, vytvoříme checkout session
			if payment.payment_method == Payment.PAYMENT.SHOP and carrier.shipping_method != Carrier.SHIPPING.STORE:
				raise serializers.ValidationError("Platba v obchodě je možná pouze pro osobní odběr.")
			
			elif payment.payment_method == Payment.PAYMENT.CASH_ON_DELIVERY and carrier.shipping_method == Carrier.SHIPPING.STORE:
				raise ValidationError("Dobírka není možná pro osobní odběr.")
			
			
			if payment.payment_method == Payment.PAYMENT.STRIPE:
				session = StripeClient.create_checkout_session(order)

				stripe_instance = StripeModel.objects.create(
					stripe_session_id=session.id,
					stripe_payment_intent=session.payment_intent,
					stripe_session_url=session.url,
					status=StripeModel.STATUS_CHOICES.PENDING
				)

				payment.stripe = stripe_instance
				payment.save(update_fields=["stripe"])

		return payment


# -- ORDER CREATE SERIALIZER --
class OrderCreateSerializer(serializers.Serializer):
	# Customer/billing data (optional when authenticated)
	first_name = serializers.CharField(required=False)
	last_name = serializers.CharField(required=False)
	email = serializers.EmailField(required=False)
	phone = serializers.CharField(required=False, allow_blank=True)
	address = serializers.CharField(required=False)
	city = serializers.CharField(required=False)
	postal_code = serializers.CharField(required=False)
	country = serializers.CharField(required=False, default="Czech Republic")
	note = serializers.CharField(required=False, allow_blank=True)

	# Nested structures
	#produkty
	items = OrderItemCreateSerializer(many=True)

	#doprava/vyzvednutí + zasilkovna input (serializer)
	carrier = OrderCarrierSerializer()

	payment = PaymentSerializer()

	#slevové kódy
	discount_codes = serializers.ListField(
		child=serializers.CharField(), required=False, allow_empty=True
	)

	def validate(self, attrs):
		request = self.context.get("request")

		#kontrola jestli je uzivatel valid/prihlasen
		is_auth = bool(getattr(getattr(request, "user", None), "is_authenticated", False))

		# pokud není, tak se musí vyplnit povinné údaje
		required_fields = [
			"first_name",
			"last_name",
			"email",
			"address",
			"city",
			"postal_code",
		]

		if not is_auth:
			missing_fields = []

			# přidame fieldy, které nejsou vyplněné
			for field in required_fields: 
				if not attrs.get(field):
					missing_fields.append(field)

			if missing_fields:
				raise serializers.ValidationError({"billing": f"Missing fields: {', '.join(missing_fields)}"})

		# pokud chybí itemy:
		if not attrs.get("items"):
			raise serializers.ValidationError({"items": "At least one item is required."})

		return attrs

	def create(self, validated_data):
		items_data = validated_data.pop("items", [])
		carrier_data = validated_data.pop("carrier")
		payment_data = validated_data.pop("payment")
		codes = validated_data.pop("discount_codes", [])

		request = self.context.get("request")
		user = getattr(request, "user", None)
		is_auth = bool(getattr(user, "is_authenticated", False))

		with transaction.atomic():
			# Create Order (user data imported on save if user is set)
			order = Order(
				user=user if is_auth else None,
				first_name=validated_data.get("first_name", ""),
				last_name=validated_data.get("last_name", ""),
				email=validated_data.get("email", ""),
				phone=validated_data.get("phone", ""),
				address=validated_data.get("address", ""),
				city=validated_data.get("city", ""),
				postal_code=validated_data.get("postal_code", ""),
				country=validated_data.get("country", "Czech Republic"),
				note=validated_data.get("note", ""),
			)

			# Order.save se postara o to jestli má doplnit data z usera
			order.save()

			# Vytvoření Carrier skrz serializer
			carrier = OrderCarrierSerializer(data=carrier_data)
			carrier.is_valid(raise_exception=True)
			carrier = carrier.save()
			order.carrier = carrier
			order.save(update_fields=["carrier", "updated_at"])  # will recalc total later


			# Vytvořit Order Items individualně, aby se spustila kontrola položek na skladu
			for item in items_data:
				product = item["product"]  # OrderItemCreateSerializer.validate
				quantity = int(item.get("quantity", 1))
				OrderItem.objects.create(order=order, product=product, quantity=quantity)


			# -- Slevové kódy --
			# Discount codes need to be added before payment/final save because calculate_total_price uses them
			if codes:
				discounts = list(DiscountCode.objects.filter(code__in=codes))
				if discounts:
					order.discount.add(*discounts)
					# Save to recalculate total with discounts
					order.save(update_fields=["total_price", "updated_at"])



			# -- Payment --
			payment_serializer = PaymentSerializer(
				data=payment_data,
				context={"order": order, "carrier": carrier}
			)
			payment_serializer.is_valid(raise_exception=True)
			payment = payment_serializer.save()

			# přiřadíme k orderu
			order.payment = payment
			order.save(update_fields=["payment", "updated_at"])
			
			return order



# ----------------- ADMIN/READ MODELS -----------------

class CategorySerializer(serializers.ModelSerializer):
	class Meta:
		model = Category
		fields = [
			"id",
			"name",
			"url",
			"parent",
			"description",
			"image",
		]


class ProductImageSerializer(serializers.ModelSerializer):
	class Meta:
		model = ProductImage
		fields = [
			"id",
			"product",
			"image",
			"alt_text",
			"is_main",
		]


class ProductSerializer(serializers.ModelSerializer):
	class Meta:
		model = Product
		fields = "__all__"
		read_only_fields = ["created_at", "updated_at"]


class DiscountCodeSerializer(serializers.ModelSerializer):
	class Meta:
		model = DiscountCode
		fields = "__all__"
		read_only_fields = ["used_count"]


class RefundSerializer(serializers.ModelSerializer):
	class Meta:
		model = Refund
		fields = "__all__"
		read_only_fields = ["id", "verified", "created_at"]


# ----------------- READ SERIALIZERS USED BY VIEWS -----------------

class ZasilkovnaPacketReadSerializer(ZasilkovnaPacketSerializer):
	class Meta(ZasilkovnaPacketSerializer.Meta):
		fields = getattr(ZasilkovnaPacketSerializer.Meta, "fields", None)


class CarrierReadSerializer(serializers.ModelSerializer):
	zasilkovna = ZasilkovnaPacketReadSerializer(many=True, read_only=True)

	class Meta:
		model = Carrier
		fields = ["shipping_method", "state", "zasilkovna", "shipping_price"]
		read_only_fields = fields


class ProductMiniSerializer(serializers.ModelSerializer):
	class Meta:
		model = Product
		fields = ["id", "name", "price"]


class OrderItemReadSerializer(serializers.ModelSerializer):
	product = ProductMiniSerializer(read_only=True)

	class Meta:
		model = OrderItem
		fields = ["id", "product", "quantity"]
		read_only_fields = fields


class PaymentReadSerializer(serializers.ModelSerializer):
	class Meta:
		model = Payment
		fields = ["payment_method"]
		read_only_fields = fields


class OrderMiniSerializer(serializers.ModelSerializer):
	status = serializers.ChoiceField(
		choices=Order.OrderStatus.choices,
		read_only=True
	)
	
	class Meta:
		model = Order
		fields = ["id", "status", "total_price", "created_at"]
		read_only_fields = fields


class OrderReadSerializer(serializers.ModelSerializer):
	status = serializers.ChoiceField(
		choices=Order.OrderStatus.choices,
		read_only=True
	)
	items = OrderItemReadSerializer(many=True, read_only=True)
	carrier = CarrierReadSerializer(read_only=True)
	payment = PaymentReadSerializer(read_only=True)
	discount_codes = serializers.SerializerMethodField()

	class Meta:
		model = Order
		fields = [
			"id",
			"status",
			"total_price",
			"currency",
			"user",
			"first_name",
			"last_name",
			"email",
			"phone",
			"address",
			"city",
			"postal_code",
			"country",
			"note",
			"created_at",
			"updated_at",
			"items",
			"carrier",
			"payment",
			"discount_codes",
		]
		read_only_fields = fields

	def get_discount_codes(self, obj: Order):
		return list(obj.discount.values_list("code", flat=True))



class ReviewSerializerPublic(serializers.ModelSerializer):

	class Meta:
		model = Review
		fields = "__all__"
		read_only_fields = ['user', 'created_at', 'updated_at']


# ----------------- CART SERIALIZERS -----------------

class CartItemSerializer(serializers.ModelSerializer):
	product_name = serializers.CharField(source='product.name', read_only=True)
	product_price = serializers.DecimalField(source='product.price', max_digits=10, decimal_places=2, read_only=True)
	subtotal = serializers.SerializerMethodField()

	class Meta:
		model = CartItem
		fields = ['id', 'product', 'product_name', 'product_price', 'quantity', 'subtotal', 'added_at']
		read_only_fields = ['id', 'added_at']

	def get_subtotal(self, obj):
		return obj.get_subtotal()

	def validate_quantity(self, value):
		if value < 1:
			raise serializers.ValidationError("Quantity must be at least 1")
		return value


class CartItemCreateSerializer(serializers.Serializer):
	product_id = serializers.IntegerField()
	quantity = serializers.IntegerField(min_value=1, default=1)

	def validate_product_id(self, value):
		try:
			Product.objects.get(pk=value, is_active=True)
		except Product.DoesNotExist:
			raise serializers.ValidationError("Product not found or inactive.")
		return value


class CartSerializer(serializers.ModelSerializer):
	items = CartItemSerializer(many=True, read_only=True)
	total = serializers.SerializerMethodField()
	items_count = serializers.SerializerMethodField()

	class Meta:
		model = Cart
		fields = ['id', 'user', 'items', 'total', 'items_count', 'created_at', 'updated_at']
		read_only_fields = ['id', 'user', 'created_at', 'updated_at']

	def get_total(self, obj):
		return obj.get_total()

	def get_items_count(self, obj):
		return obj.get_items_count()


# ----------------- WISHLIST SERIALIZERS -----------------

class ProductMiniForWishlistSerializer(serializers.ModelSerializer):
	"""Minimal product info for wishlist display"""
	class Meta:
		model = Product
		fields = ['id', 'name', 'price', 'is_active', 'stock']


class WishlistSerializer(serializers.ModelSerializer):
	products = ProductMiniForWishlistSerializer(many=True, read_only=True)
	products_count = serializers.SerializerMethodField()

	class Meta:
		model = Wishlist
		fields = ['id', 'user', 'products', 'products_count', 'created_at', 'updated_at']
		read_only_fields = ['id', 'user', 'created_at', 'updated_at']

	def get_products_count(self, obj):
		return obj.get_products_count()


class WishlistProductActionSerializer(serializers.Serializer):
	"""For adding/removing products from wishlist"""
	product_id = serializers.IntegerField()

	def validate_product_id(self, value):
		try:
			Product.objects.get(pk=value, is_active=True)
		except Product.DoesNotExist:
			raise serializers.ValidationError("Product not found or inactive.")
		return value