// Copyright 2026 MarketAlly. All rights reserved.
// SPDX-License-Identifier: MIT

package v2

import (
	"net/http"

	apierrors "code.gitea.io/gitea/modules/errors"
	"code.gitea.io/gitea/modules/operations"
	"code.gitea.io/gitea/services/context"
)

// OperationProgressResponse represents an operation progress response
type OperationProgressResponse struct {
	OperationID  string  `json:"operation_id"`
	Type         string  `json:"type"`
	Status       string  `json:"status"`
	CurrentPhase string  `json:"current_phase,omitempty"`
	Phases       []Phase `json:"phases,omitempty"`
	Progress     int     `json:"progress"`
	BytesTotal   int64   `json:"bytes_total,omitempty"`
	BytesDone    int64   `json:"bytes_done,omitempty"`
	ItemsTotal   int     `json:"items_total,omitempty"`
	ItemsDone    int     `json:"items_done,omitempty"`
	Message      string  `json:"message,omitempty"`
	Error        string  `json:"error,omitempty"`
	StartedAt    string  `json:"started_at"`
	UpdatedAt    string  `json:"updated_at"`
	EstimatedETA string  `json:"estimated_eta,omitempty"`
	SpeedBPS     int64   `json:"speed_bps,omitempty"`
}

// Phase represents a phase in an operation
type Phase struct {
	Name     string `json:"name"`
	Status   string `json:"status"`
	Progress int    `json:"progress"`
	Message  string `json:"message,omitempty"`
}

// OperationProgress streams operation progress via SSE
// @Summary Stream operation progress
// @Description Streams real-time progress updates for a long-running operation via Server-Sent Events
// @Tags operations
// @Produce text/event-stream
// @Param id path string true "Operation ID"
// @Success 200 {object} OperationProgressResponse "SSE stream of progress updates"
// @Failure 404 {object} map[string]any
// @Router /operations/{id}/progress [get]
func OperationProgress(ctx *context.APIContext) {
	opID := ctx.PathParam("id")

	// ServeSSE handles all the response logic
	operations.ServeSSE(ctx.Resp, ctx.Req, opID)
}

// GetOperation retrieves the current state of an operation
// @Summary Get operation status
// @Description Returns the current status of a long-running operation
// @Tags operations
// @Produce json
// @Param id path string true "Operation ID"
// @Success 200 {object} OperationProgressResponse
// @Failure 404 {object} map[string]any
// @Router /operations/{id} [get]
func GetOperation(ctx *context.APIContext) {
	opID := ctx.PathParam("id")

	manager := operations.GetManager()
	op, ok := manager.GetOperation(opID)
	if !ok {
		ctx.APIErrorWithCode(apierrors.ResourceNotFound, map[string]any{
			"resource": "operation",
			"id":       opID,
		})
		return
	}

	progress := op.GetProgress()

	// Convert phases
	phases := make([]Phase, len(progress.Phases))
	for i, p := range progress.Phases {
		phases[i] = Phase{
			Name:     p.Name,
			Status:   string(p.Status),
			Progress: p.Progress,
			Message:  p.Message,
		}
	}

	response := OperationProgressResponse{
		OperationID:  progress.OperationID,
		Type:         string(progress.Type),
		Status:       string(progress.Status),
		CurrentPhase: progress.CurrentPhase,
		Phases:       phases,
		Progress:     progress.Progress,
		BytesTotal:   progress.BytesTotal,
		BytesDone:    progress.BytesDone,
		ItemsTotal:   progress.ItemsTotal,
		ItemsDone:    progress.ItemsDone,
		Message:      progress.Message,
		Error:        progress.Error,
		StartedAt:    progress.StartedAt.Format("2006-01-02T15:04:05Z07:00"),
		UpdatedAt:    progress.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
		SpeedBPS:     progress.SpeedBPS,
	}

	if progress.EstimatedETA != nil {
		response.EstimatedETA = progress.EstimatedETA.Format("2006-01-02T15:04:05Z07:00")
	}

	ctx.JSON(http.StatusOK, response)
}

// CancelOperation cancels a running operation
// @Summary Cancel operation
// @Description Cancels a long-running operation if possible
// @Tags operations
// @Produce json
// @Param id path string true "Operation ID"
// @Success 200 {object} map[string]any
// @Failure 404 {object} map[string]any
// @Router /operations/{id} [delete]
func CancelOperation(ctx *context.APIContext) {
	opID := ctx.PathParam("id")

	manager := operations.GetManager()
	op, ok := manager.GetOperation(opID)
	if !ok {
		ctx.APIErrorWithCode(apierrors.ResourceNotFound, map[string]any{
			"resource": "operation",
			"id":       opID,
		})
		return
	}

	op.Cancel()

	ctx.JSON(http.StatusOK, map[string]any{
		"operation_id": opID,
		"status":       "cancelled",
		"message":      "Operation cancellation requested",
	})
}
