package ai_pipeline

import (
	"errors"
	"fmt"
	"net/http"

	"tm/pkg/ai_summarizer"
	"tm/pkg/response"

	"github.com/labstack/echo/v4"
)

// Handler handles admin HTTP requests for Opplens AI pipeline operations.
type Handler struct {
	service Service
}

// NewHandler creates a new AI pipeline handler.
func NewHandler(service Service) *Handler {
	return &Handler{service: service}
}

// ScrapeDocuments scrapes documents for one tender via the Opplens AI service.
// @Summary Scrape tender documents
// @Description Download all documents for one tender through the Opplens AI service (synchronous, cached)
// @Tags Admin-AI-Pipeline
// @Accept json
// @Produce json
// @Param request body ScrapeDocumentsForm true "Tender identifiers"
// @Success 200 {object} response.APIResponse{data=ai_summarizer.ScrapeDocumentsResponse}
// @Failure 400 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 422 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/scrape/documents [post]
func (h *Handler) ScrapeDocuments(c echo.Context) error {
	form, err := response.Parse[ScrapeDocumentsForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}

	result, err := h.service.ScrapeDocuments(c.Request().Context(), *form)
	if err != nil {
		return mapPipelineHTTPError(c, err, "Scrape documents")
	}

	return response.Success(c, result, "Documents scraped successfully")
}

// ScrapeDocumentsBatch enqueues background document scraping for many tenders.
// @Summary Batch scrape tender documents
// @Description Enqueue background document scraping for multiple tenders via the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Accept json
// @Produce json
// @Param request body TenderBatchForm true "Tenders to scrape"
// @Success 202 {object} response.APIResponse{data=ai_summarizer.BatchAcceptedResponse}
// @Failure 400 {object} response.APIResponse
// @Failure 422 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/scrape/documents/batch [post]
func (h *Handler) ScrapeDocumentsBatch(c echo.Context) error {
	form, err := response.Parse[TenderBatchForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}

	result, err := h.service.ScrapeDocumentsBatch(c.Request().Context(), *form)
	if err != nil {
		return mapPipelineHTTPError(c, err, "Scrape documents batch")
	}

	return response.Accepted(c, result, "Scrape batch accepted")
}

// GetScrapePortals lists document scraping portals supported by the Opplens AI service.
// @Summary List document scraping portals
// @Description Retrieve the list of document scraping portals supported by the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Produce json
// @Success 200 {object} response.APIResponse{data=[]string} "Scrape portals retrieved successfully"
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/scrape/portals [get]
func (h *Handler) GetScrapePortals(c echo.Context) error {
	result, err := h.service.GetScrapePortals(c.Request().Context())
	if err != nil {
		return mapPipelineHTTPError(c, err, "Get scrape portals")
	}

	return response.Success(c, result, "Scrape portals retrieved successfully")
}

// SummarizeBatch enqueues background summarization for many tenders.
// @Summary Batch summarize tenders
// @Description Enqueue background AI summarization for multiple tenders via the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Accept json
// @Produce json
// @Param request body TenderBatchForm true "Tenders to summarize"
// @Success 202 {object} response.APIResponse{data=ai_summarizer.BatchAcceptedResponse}
// @Failure 400 {object} response.APIResponse
// @Failure 422 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/summarize/batch [post]
func (h *Handler) SummarizeBatch(c echo.Context) error {
	form, err := response.Parse[TenderBatchForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}

	result, err := h.service.SummarizeBatch(c.Request().Context(), *form)
	if err != nil {
		return mapPipelineHTTPError(c, err, "Summarize batch")
	}

	return response.Accepted(c, result, "Summarize batch accepted")
}

// TranslateBatch enqueues background translation for many tenders.
// @Summary Batch translate tenders
// @Description Enqueue background AI translation for multiple tenders via the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Accept json
// @Produce json
// @Param request body TranslateBatchForm true "Tenders and target languages"
// @Success 202 {object} response.APIResponse{data=ai_summarizer.BatchAcceptedResponse}
// @Failure 400 {object} response.APIResponse
// @Failure 422 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/translate/batch [post]
func (h *Handler) TranslateBatch(c echo.Context) error {
	form, err := response.Parse[TranslateBatchForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}

	result, err := h.service.TranslateBatch(c.Request().Context(), *form)
	if err != nil {
		return mapPipelineHTTPError(c, err, "Translate batch")
	}

	return response.Accepted(c, result, "Translate batch accepted")
}

// Sync pulls the tender list from this backend into the Opplens AI service.
// @Summary Sync tenders to AI pipeline
// @Description Pull the tender list from the backend and store it in the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Produce json
// @Success 200 {object} response.APIResponse{data=ai_summarizer.PipelineSyncResponse}
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/sync [post]
func (h *Handler) Sync(c echo.Context) error {
	result, err := h.service.Sync(c.Request().Context())
	if err != nil {
		return mapPipelineHTTPError(c, err, "Pipeline sync")
	}

	return response.Success(c, result, "Pipeline sync completed successfully")
}

// Run runs the full AI pipeline for one tender (scrape → translate → summarize).
// @Summary Run full AI pipeline for one tender
// @Description Run scrape, translate, and summarize for one tender via the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Accept json
// @Produce json
// @Param request body PipelineRunForm true "Tender and languages"
// @Success 200 {object} response.APIResponse{data=object}
// @Failure 400 {object} response.APIResponse
// @Failure 404 {object} response.APIResponse
// @Failure 422 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/run [post]
func (h *Handler) Run(c echo.Context) error {
	form, err := response.Parse[PipelineRunForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}

	result, err := h.service.Run(c.Request().Context(), *form)
	if err != nil {
		return mapPipelineHTTPError(c, err, "Pipeline run")
	}

	return response.Success(c, result, "Pipeline run completed successfully")
}

// RunBatch enqueues the full AI pipeline for many tenders.
// @Summary Batch run full AI pipeline
// @Description Enqueue scrape, translate, and summarize for multiple tenders via the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Accept json
// @Produce json
// @Param request body PipelineRunBatchForm true "Tenders and languages"
// @Success 202 {object} response.APIResponse{data=ai_summarizer.BatchAcceptedResponse}
// @Failure 400 {object} response.APIResponse
// @Failure 422 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/run/batch [post]
func (h *Handler) RunBatch(c echo.Context) error {
	form, err := response.Parse[PipelineRunBatchForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid request data", err.Error())
	}

	result, err := h.service.RunBatch(c.Request().Context(), *form)
	if err != nil {
		return mapPipelineHTTPError(c, err, "Pipeline run batch")
	}

	return response.Accepted(c, result, "Pipeline run batch accepted")
}

// Analyze triggers analysis across stored tenders in the Opplens AI service.
// @Summary Trigger AI analysis pipeline
// @Description Trigger agentic analysis across stored tenders via the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Produce json
// @Success 200 {object} response.APIResponse{data=ai_summarizer.PipelineActionResponse}
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/analyze [post]
func (h *Handler) Analyze(c echo.Context) error {
	result, err := h.service.Analyze(c.Request().Context())
	if err != nil {
		return mapPipelineHTTPError(c, err, "Pipeline analyze")
	}

	return response.Success(c, result, "Pipeline analyze triggered successfully")
}

// DailyRun syncs tenders and runs the full pipeline on newly synced tenders.
// @Summary Start daily AI pipeline run
// @Description Sync tenders, then run the full pipeline on newly synced tenders (background, single-flight)
// @Tags Admin-AI-Pipeline
// @Produce json
// @Success 202 {object} response.APIResponse{data=ai_summarizer.PipelineStartedResponse}
// @Failure 409 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/daily-run [post]
func (h *Handler) DailyRun(c echo.Context) error {
	result, err := h.service.DailyRun(c.Request().Context())
	if err != nil {
		return mapPipelineHTTPError(c, err, "Pipeline daily-run")
	}

	return response.Accepted(c, result, "Pipeline daily-run started")
}

// Auto syncs tenders and completes all missing AI work across stored tenders.
// @Summary Start auto AI pipeline run
// @Description Sync tenders, then complete all missing scrape/translate/summarize work (background, single-flight, idempotent)
// @Tags Admin-AI-Pipeline
// @Produce json
// @Success 202 {object} response.APIResponse{data=ai_summarizer.PipelineStartedResponse}
// @Failure 409 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/auto [post]
func (h *Handler) Auto(c echo.Context) error {
	result, err := h.service.Auto(c.Request().Context())
	if err != nil {
		return mapPipelineHTTPError(c, err, "Pipeline auto")
	}

	return response.Accepted(c, result, "Pipeline auto started")
}

// GetLastRun returns the result of the last daily-run.
// @Summary Get last daily-run report
// @Description Retrieve the report for the last pipeline daily-run from the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Produce json
// @Success 200 {object} response.APIResponse{data=ai_summarizer.PipelineReportResponse}
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/last-run [get]
func (h *Handler) GetLastRun(c echo.Context) error {
	result, err := h.service.GetLastRun(c.Request().Context())
	if err != nil {
		return mapPipelineHTTPError(c, err, "Get last pipeline run")
	}

	return response.Success(c, result, "Last pipeline run retrieved successfully")
}

// GetLastAutoRun returns the result of the last auto run.
// @Summary Get last auto-run report
// @Description Retrieve the report for the last pipeline auto run from the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Produce json
// @Success 200 {object} response.APIResponse{data=ai_summarizer.PipelineReportResponse}
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/last-auto-run [get]
func (h *Handler) GetLastAutoRun(c echo.Context) error {
	result, err := h.service.GetLastAutoRun(c.Request().Context())
	if err != nil {
		return mapPipelineHTTPError(c, err, "Get last pipeline auto run")
	}

	return response.Success(c, result, "Last pipeline auto run retrieved successfully")
}

// GetReport returns an event-log summary for a time window.
// @Summary Get AI pipeline event report
// @Description Retrieve an event-log summary for a time window from the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Produce json
// @Param window query string false "Time window" Enums(last_hour,last_24h,today,yesterday,last_7_days,last_30_days,all,daily) default(last_24h)
// @Success 200 {object} response.APIResponse{data=ai_summarizer.PipelineReportResponse}
// @Failure 400 {object} response.APIResponse
// @Failure 422 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/report [get]
func (h *Handler) GetReport(c echo.Context) error {
	form, err := response.Parse[PipelineWindowQueryForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid query parameters", err.Error())
	}

	result, err := h.service.GetReport(c.Request().Context(), form.Window)
	if err != nil {
		return mapPipelineHTTPError(c, err, "Get pipeline report")
	}

	return response.Success(c, result, "Pipeline report retrieved successfully")
}

// GetStats returns event-log and storage inventory for a time window.
// @Summary Get AI pipeline stats
// @Description Retrieve event-log summary and MinIO inventory for a time window from the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Produce json
// @Param window query string false "Time window" Enums(last_hour,last_24h,today,yesterday,last_7_days,last_30_days,all,daily) default(last_24h)
// @Success 200 {object} response.APIResponse{data=ai_summarizer.PipelineStatsResponse}
// @Failure 400 {object} response.APIResponse
// @Failure 422 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/stats [get]
func (h *Handler) GetStats(c echo.Context) error {
	form, err := response.Parse[PipelineWindowQueryForm](c)
	if err != nil {
		return response.ValidationError(c, "Invalid query parameters", err.Error())
	}

	result, err := h.service.GetStats(c.Request().Context(), form.Window)
	if err != nil {
		return mapPipelineHTTPError(c, err, "Get pipeline stats")
	}

	return response.Success(c, result, "Pipeline stats retrieved successfully")
}

// GetMinioStats returns storage inventory from the Opplens AI service.
// @Summary Get AI pipeline MinIO stats
// @Description Retrieve storage inventory only from the Opplens AI service
// @Tags Admin-AI-Pipeline
// @Produce json
// @Success 200 {object} response.APIResponse{data=ai_summarizer.PipelineMinioStatsResponse}
// @Failure 500 {object} response.APIResponse
// @Failure 503 {object} response.APIResponse
// @Security BearerAuth
// @Router /admin/v1/ai-pipeline/minio-stats [get]
func (h *Handler) GetMinioStats(c echo.Context) error {
	result, err := h.service.GetMinioStats(c.Request().Context())
	if err != nil {
		return mapPipelineHTTPError(c, err, "Get pipeline minio stats")
	}

	return response.Success(c, result, "Pipeline MinIO stats retrieved successfully")
}

func mapPipelineHTTPError(c echo.Context, err error, action string) error {
	switch {
	case errors.Is(err, ErrAINotConfigured):
		return response.ServiceUnavailable(c, "AI service is not configured")
	case errors.Is(err, ErrEmptyTenderBatch), errors.Is(err, ErrEmptyLanguages):
		return response.BadRequest(c, "Invalid request", err.Error())
	case errors.Is(err, ai_summarizer.ErrPipelineJobRunning):
		return response.Conflict(c, "A pipeline job is already running")
	case errors.Is(err, ai_summarizer.ErrObjectNotFound):
		return response.NotFound(c, "Tender not found in AI service")
	}

	var upstream *ai_summarizer.APIStatusError
	if errors.As(err, &upstream) {
		details := upstream.Body
		if details == "" {
			details = fmt.Sprintf("upstream status %d", upstream.StatusCode)
		}

		switch upstream.StatusCode {
		case http.StatusNotFound:
			return response.NotFound(c, "Tender not found in AI service")
		case http.StatusUnprocessableEntity:
			return response.ValidationError(c, "AI service rejected the request", details)
		case http.StatusBadGateway:
			return c.JSON(http.StatusBadGateway, response.APIResponse{
				Success: false,
				Message: action + " failed",
				Error: &response.APIError{
					Code:    "UPSTREAM_AI_ERROR",
					Message: "Opplens AI service returned status 502",
					Details: details,
				},
			})
		default:
			return c.JSON(http.StatusBadGateway, response.APIResponse{
				Success: false,
				Message: action + " failed",
				Error: &response.APIError{
					Code:    "UPSTREAM_AI_ERROR",
					Message: fmt.Sprintf("Opplens AI service returned status %d", upstream.StatusCode),
					Details: details,
				},
			})
		}
	}

	return response.InternalServerError(c, action+" failed")
}
