from __future__ import annotations
# Tato aplikace poskytuje samostatné HTTP API pro GoPay, připravené k připojení do e‑shopu.
# Pohledy volají GoPay SDK a ukládají minimální data o životním cyklu (platby/refundy).
# Koncové body jsou dokumentovány pro Swagger/Redoc pomocí drf-spectacular.

from rest_framework import permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView
from drf_spectacular.utils import (
    extend_schema,
    OpenApiParameter,
    OpenApiResponse,
    OpenApiExample,
    OpenApiTypes,
)
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured

import gopay
from gopay.enums import TokenScope, Language


def payments_client():
	"""Create a fresh GoPay payments client from settings.

	Keeps it simple and explicit; no shared global state.
	"""
	required = [
		("GOPAY_GOID", settings.GOPAY_GOID),
		("GOPAY_CLIENT_ID", settings.GOPAY_CLIENT_ID),
		("GOPAY_CLIENT_SECRET", settings.GOPAY_CLIENT_SECRET),
		("GOPAY_GATEWAY_URL", settings.GOPAY_GATEWAY_URL),
	]
	missing = [name for name, val in required if not val]
	if missing:
		raise ImproperlyConfigured(f"Missing GoPay settings: {', '.join(missing)}")

	cfg = {
		"goid": settings.GOPAY_GOID,
		"client_id": settings.GOPAY_CLIENT_ID,
		"client_secret": settings.GOPAY_CLIENT_SECRET,
		"gateway_url": settings.GOPAY_GATEWAY_URL,
		# reasonable defaults; can be changed later via settings if desired
		"scope": TokenScope.ALL,
		"language": Language.CZECH,
	}
	return gopay.payments(cfg)


from .models import GoPayPayment, GoPayRefund
from .serializers import (
    PaymentCreateSerializer,
    RefundSerializer,
)


class CreatePaymentView(APIView):
	"""Vytvoří novou platbu v GoPay a uloží odpověď lokálně.

	Typický e‑shop flow:
	- Frontend zavolá tento endpoint s GoPay payloadem.
	- Backend předá payload GoPay SDK a vrátí upstream odpověď.
	- Vznikne lokální záznam GoPayPayment pro pozdější sledování stavu.
	"""
	permission_classes = [permissions.IsAuthenticated]

	@extend_schema(
		tags=["gopay"],
		operation_id="gopay_create_payment",
		summary="Vytvořit platbu (minimální vstup)",
		description=(
			"Vytvoří platbu v GoPay s minimálními povinnými poli. Citlivé údaje o kartě se neposílají,"
			" platbu obslouží GoPay stránka (gw_url). Pokud není zadán notification_url, použije se"
			" hodnota ze settings.GOPAY_NOTIFICATION_URL."
		),
		request=PaymentCreateSerializer,
		responses={
			201: OpenApiResponse(
				response=OpenApiTypes.OBJECT,
				description="Platba vytvořena. Vrací gw_url pro přesměrování na platební bránu."
			),
			502: OpenApiResponse(description="Chyba upstream GoPay"),
		},
		examples=[
			OpenApiExample(
				"Minimální platba",
				value={
					"payment": {
						"amount": 10000,
						"currency": "CZK",
						"order_number": "123456",
						"payer": {"contact": {"email": "john.doe@example.com"}},
						"callback": {
							"return_url": "https://example.com/your-return-url",
							"notification_url": "https://example.com/your-notify-url"
						}
					}
				},
			)
		],

	)
	def post(self, request):
		ser = PaymentCreateSerializer(data=request.data)
		ser.is_valid(raise_exception=True)
		payload = ser.validated_data["payment"]

		try:
			res = payments_client().create_payment(payload)  # Expecting dict-like/dict response
		except Exception as e:
			return Response({"detail": str(e)}, status=status.HTTP_502_BAD_GATEWAY)

		# Map fields defensively
		as_dict = res if isinstance(res, dict) else getattr(res, "__dict__", {}) or {}
		gopay_id = str(as_dict.get("id", ""))
		status_text = str(as_dict.get("state", ""))
		amount = int(as_dict.get("amount", payload.get("amount", 0)) or 0)
		currency = as_dict.get("currency", payload.get("currency", ""))
		gw_url = as_dict.get("gw_url") or as_dict.get("gwUrl") or as_dict.get("gw-url")

		payment = GoPayPayment.objects.create(
			user=request.user if request.user and request.user.is_authenticated else None,
			gopay_id=gopay_id or payload.get("id", ""),
			order_number=str(payload.get("order_number", "")),
			amount=amount,
			currency=currency or "",
			status=status_text,
			preauthorized=bool(payload.get("preauthorize", False)),
			request_payload=payload,
			response_payload=as_dict or {"raw": str(res)},
		)

		return Response(
			{
				"payment_id": payment.gopay_id,
				"state": payment.status,
				"gw_url": gw_url,
				"raw": payment.response_payload,
			},
			status=status.HTTP_201_CREATED,
		)


class PaymentStatusView(APIView):
	"""Načte aktuální stav platby GoPay a případně synchronizuje lokální záznam."""
	permission_classes = [permissions.IsAuthenticated]

	@extend_schema(
		tags=["gopay"],
		operation_id="gopay_get_status",
		summary="Získat stav platby",
		parameters=[
			OpenApiParameter(
				name="payment_id",
				type=OpenApiTypes.STR,
				location=OpenApiParameter.PATH,
				description="ID platby GoPay",
			)
		],
		responses={
			200: OpenApiResponse(OpenApiTypes.OBJECT, description="Aktuální stav platby"),
			502: OpenApiResponse(description="Chyba upstream GoPay"),
		},
	)
	def get(self, request, payment_id: str | int):
		try:
			res = payments_client().get_status(payment_id)
		except Exception as e:
			return Response({"detail": str(e)}, status=status.HTTP_502_BAD_GATEWAY)

		# Normalize GoPay SDK response into a dict body
		body = None
		if hasattr(res, "success") and hasattr(res, "json"):
			# Official SDK-style: check success and extract JSON body
			ok = bool(getattr(res, "success", False))
			if not ok:
				return Response({"detail": "GoPay upstream error", "success": False}, status=status.HTTP_502_BAD_GATEWAY)
			json_attr = getattr(res, "json")
			body = json_attr() if callable(json_attr) else json_attr
		elif isinstance(res, dict):
			body = res
		else:
			body = getattr(res, "__dict__", {}) or {"raw": str(res)}

		state_val = body.get("state") if isinstance(body, dict) else None

		# Update local status if we have it
		try:
			local = GoPayPayment.objects.get(gopay_id=str(payment_id))
			if state_val:
				local.status = state_val
				local.response_payload = body if isinstance(body, dict) else {"raw": str(body)}
				local.save(update_fields=["status", "response_payload", "updated_at"])
		except GoPayPayment.DoesNotExist:
			pass

		return Response(body, status=status.HTTP_200_OK)


class RefundPaymentView(APIView):
	"""Provede refundaci platby v GoPay a uloží záznam refundace."""
	permission_classes = [permissions.IsAuthenticated]

	@extend_schema(
		tags=["gopay"],
		operation_id="gopay_refund_payment",
		summary="Refundovat platbu",
		parameters=[
			OpenApiParameter(
				name="payment_id",
				type=OpenApiTypes.STR,
				location=OpenApiParameter.PATH,
				description="ID platby GoPay k refundaci",
			)
		],
		request=RefundSerializer,
		responses={
			200: OpenApiResponse(OpenApiTypes.OBJECT, description="Výsledek refundace"),
			502: OpenApiResponse(description="Chyba upstream GoPay"),
		},
	)
	def post(self, request, payment_id: str | int):
		ser = RefundSerializer(data=request.data)
		ser.is_valid(raise_exception=True)
		amount = ser.validated_data["amount"]

		try:
			res = payments_client().refund_payment(payment_id, amount)
		except Exception as e:
			return Response({"detail": str(e)}, status=status.HTTP_502_BAD_GATEWAY)

		payment = GoPayPayment.objects.filter(gopay_id=str(payment_id)).first()

		ref = GoPayRefund.objects.create(
			payment=payment,
			gopay_refund_id=str((res.get("id") if isinstance(res, dict) else getattr(res, "id", "")) or ""),
			amount=amount,
			status=(res.get("state") if isinstance(res, dict) else getattr(res, "state", "")) or "",
			payload=res if isinstance(res, dict) else {"raw": str(res)},
		)

		return Response({"refund": ref.payload}, status=status.HTTP_200_OK)
