"""
M2M (Machine-to-Machine) GraphQL schema for Exchange.
Used by internal services (Temporal workflows, etc.) without user authentication.
"""
import graphene
import logging
from graphene_django import DjangoObjectType
from offers.models import Offer

logger = logging.getLogger(__name__)


class OfferType(DjangoObjectType):
    class Meta:
        model = Offer
        fields = "__all__"


class M2MQuery(graphene.ObjectType):
    offer = graphene.Field(OfferType, offerUuid=graphene.String(required=True))

    def resolve_offer(self, info, offerUuid):
        try:
            return Offer.objects.get(uuid=offerUuid)
        except Offer.DoesNotExist:
            return None


class CreateOfferFromWorkflowInput(graphene.InputObjectType):
    offerUuid = graphene.String(required=True)
    teamUuid = graphene.String(required=True)
    productUuid = graphene.String(required=True)
    productName = graphene.String(required=True)
    categoryName = graphene.String()
    locationUuid = graphene.String()
    locationName = graphene.String()
    locationCountry = graphene.String()
    locationCountryCode = graphene.String()
    locationLatitude = graphene.Float()
    locationLongitude = graphene.Float()
    quantity = graphene.Decimal(required=True)
    unit = graphene.String()
    pricePerUnit = graphene.Decimal()
    currency = graphene.String()
    description = graphene.String()
    validUntil = graphene.Date()
    terminusSchemaId = graphene.String()
    terminusDocumentId = graphene.String()


class CreateOfferFromWorkflow(graphene.Mutation):
    class Arguments:
        input = CreateOfferFromWorkflowInput(required=True)

    success = graphene.Boolean()
    message = graphene.String()
    offer = graphene.Field(OfferType)

    def mutate(self, info, input):
        try:
            offer = Offer.objects.filter(uuid=input.offerUuid).first()
            if offer:
                logger.info("Offer %s already exists, returning existing", input.offerUuid)
                return CreateOfferFromWorkflow(success=True, message="Offer exists", offer=offer)

            offer = Offer.objects.create(
                uuid=input.offerUuid,
                team_uuid=input.teamUuid,
                product_uuid=input.productUuid,
                product_name=input.productName,
                category_name=input.categoryName or '',
                location_uuid=input.locationUuid or '',
                location_name=input.locationName or '',
                location_country=input.locationCountry or '',
                location_country_code=input.locationCountryCode or '',
                location_latitude=input.locationLatitude,
                location_longitude=input.locationLongitude,
                quantity=input.quantity,
                unit=input.unit or 'ton',
                price_per_unit=input.pricePerUnit,
                currency=input.currency or 'USD',
                description=input.description or '',
                valid_until=input.validUntil,
                terminus_schema_id=input.terminusSchemaId or '',
                terminus_document_id=input.terminusDocumentId or '',
                workflow_status='pending',
            )
            logger.info("Created offer %s via workflow", offer.uuid)
            return CreateOfferFromWorkflow(success=True, message="Offer created", offer=offer)
        except Exception as exc:
            logger.exception("Failed to create offer %s", input.offerUuid)
            return CreateOfferFromWorkflow(success=False, message=str(exc), offer=None)


class UpdateOfferWorkflowStatusInput(graphene.InputObjectType):
    offerUuid = graphene.String(required=True)
    status = graphene.String(required=True)  # pending | active | error
    errorMessage = graphene.String()


class UpdateOfferWorkflowStatus(graphene.Mutation):
    class Arguments:
        input = UpdateOfferWorkflowStatusInput(required=True)

    success = graphene.Boolean()
    message = graphene.String()
    offer = graphene.Field(OfferType)

    def mutate(self, info, input):
        try:
            offer = Offer.objects.get(uuid=input.offerUuid)
            offer.workflow_status = input.status
            if input.errorMessage is not None:
                offer.workflow_error = input.errorMessage
            offer.save(update_fields=["workflow_status", "workflow_error", "updated_at"])
            logger.info("Offer %s workflow_status updated to %s", input.offerUuid, input.status)
            return UpdateOfferWorkflowStatus(success=True, message="Status updated", offer=offer)
        except Offer.DoesNotExist:
            return UpdateOfferWorkflowStatus(success=False, message="Offer not found", offer=None)


class M2MMutation(graphene.ObjectType):
    createOfferFromWorkflow = CreateOfferFromWorkflow.Field()
    updateOfferWorkflowStatus = UpdateOfferWorkflowStatus.Field()


m2m_schema = graphene.Schema(query=M2MQuery, mutation=M2MMutation)
