package dialectsfcrm

import (
	"context"
	"errors"
	"net/http"

	"github.com/nexuscrm/dialect-sf-crm/wire"
	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/dialect"
)

const connectorSyncStatusTimeLayout = "2006-01-02T15:04:05.000Z07:00"

type connectorSyncStatusDTO struct {
	ConnectorOwnerKey  string  `json:"connectorOwnerKey"`
	ActionType         string  `json:"actionType"`
	DestinationSlotID  string  `json:"destinationSlotId"`
	TargetObject       string  `json:"targetObject"`
	LinkStatus         *string `json:"linkStatus,omitempty"`
	LastAttemptStatus  *string `json:"lastAttemptStatus,omitempty"`
	ResponseStatusCode *int64  `json:"responseStatusCode,omitempty"`
	LastErrorAt        *string `json:"lastErrorAt,omitempty"`
}

func AdminConnectorSyncStatusNeutralHandler(ctx context.Context, req *dialect.Request, deps dialect.Deps) (*dialect.Response, error) {
	objectName := firstQuery(req, "object")
	recordID := firstQuery(req, "recordId")
	if objectName == "" || recordID == "" {
		return &dialect.Response{
			Status: http.StatusBadRequest,
			Body:   wire.SFErrorResponse(wire.SFCodeRequiredFieldMissing, "object and recordId query parameters are required"),
		}, nil
	}
	if req == nil || req.User == nil {
		return &dialect.Response{
			Status: http.StatusUnauthorized,
			Body:   wire.SFErrorResponse(wire.SFCodeInvalidSessionID, "authentication required"),
		}, nil
	}

	syncStatus := deps.Contracts.ConnectorSyncStatus
	if syncStatus == nil {
		return connectorSyncStatusInternalResponse(), nil
	}
	result, err := syncStatus.GetConnectorSyncStatus(ctx, req.User, objectName, recordID)
	if err != nil {
		return connectorSyncStatusErrorResponse(err), nil
	}
	if result == nil {
		result = &contract.ConnectorSyncStatusResult{Object: objectName, RecordID: recordID}
	}

	rows := make([]connectorSyncStatusDTO, 0, len(result.SyncStatuses))
	for _, state := range result.SyncStatuses {
		dto := connectorSyncStatusDTO{
			ConnectorOwnerKey:  state.ConnectorOwnerKey,
			ActionType:         state.ActionType,
			DestinationSlotID:  state.DestinationSlotID,
			TargetObject:       state.TargetObject,
			LinkStatus:         state.LinkStatus,
			LastAttemptStatus:  state.LastAttemptStatus,
			ResponseStatusCode: state.ResponseStatusCode,
		}
		if state.LastErrorAt != nil {
			value := state.LastErrorAt.UTC().Format(connectorSyncStatusTimeLayout)
			dto.LastErrorAt = &value
		}
		rows = append(rows, dto)
	}

	objectOut := result.Object
	if objectOut == "" {
		objectOut = objectName
	}
	recordIDOut := result.RecordID
	if recordIDOut == "" {
		recordIDOut = recordID
	}
	return jsonResponse(http.StatusOK, map[string]any{
		"object":       objectOut,
		"recordId":     recordIDOut,
		"syncStatuses": rows,
	}), nil
}

func connectorSyncStatusErrorResponse(err error) *dialect.Response {
	var statusErr *contract.ConnectorSyncStatusError
	if errors.As(err, &statusErr) {
		switch statusErr.Kind {
		case contract.ConnectorSyncStatusErrorForbidden:
			return &dialect.Response{Status: http.StatusForbidden, Body: wire.SFErrorResponse(wire.SFCodeForbidden, statusErr.Message)}
		case contract.ConnectorSyncStatusErrorNotFound:
			return &dialect.Response{Status: http.StatusNotFound, Body: wire.SFErrorResponse(wire.SFCodeNotFound, statusErr.Message)}
		case contract.ConnectorSyncStatusErrorInternal:
			return &dialect.Response{Status: http.StatusInternalServerError, Body: wire.SFErrorResponse(wire.SFCodeInternalError, statusErr.Message)}
		}
	}
	return connectorSyncStatusInternalResponse()
}

func connectorSyncStatusInternalResponse() *dialect.Response {
	return &dialect.Response{
		Status: http.StatusInternalServerError,
		Body:   wire.SFErrorResponse(wire.SFCodeInternalError, "An internal server error occurred. Contact your system administrator."),
	}
}
