package labelstudio

import (
	"encoding/json"
	"fmt"
	"net/url"
	"time"

	"source.gleipnir.technology/Gleipnir/nidus-sync/lint"
)

// TasksListResponse represents the response from the /api/tasks endpoint
type TasksListResponse struct {
	Tasks            []Task `json:"tasks"`
	Total            int    `json:"total"`
	TotalAnnotations int    `json:"total_annotations"`
	TotalPredictions int    `json:"total_predictions"`
}

// Task represents a single task returned by the Label Studio API
type Task struct {
	Agreement                string                   `json:"agreement"`
	AgreementSelected        string                   `json:"agreement_selected"`
	Annotations              json.RawMessage          `json:"annotations"`
	AnnotationsIDs           json.RawMessage          `json:"annotations_ids"`
	AnnotationsResults       json.RawMessage          `json:"annotations_results"`
	Annotators               []int                    `json:"annotators"`
	AnnotatorsCount          int                      `json:"annotators_count"`
	AvgLeadTime              float64                  `json:"avg_lead_time"`
	CancelledAnnotations     int                      `json:"cancelled_annotations"`
	CommentAuthors           []map[string]interface{} `json:"comment_authors"`
	CommentAuthorsCount      int                      `json:"comment_authors_count"`
	CommentCount             int                      `json:"comment_count"`
	Comments                 json.RawMessage          `json:"comments"`
	CompletedAt              string                   `json:"completed_at"`
	CreatedAt                time.Time                `json:"created_at"`
	Data                     map[string]interface{}   `json:"data"`
	DraftExists              bool                     `json:"draft_exists"`
	Drafts                   []json.RawMessage        `json:"drafts"`
	FileUpload               string                   `json:"file_upload"`
	GroundTruth              bool                     `json:"ground_truth"`
	ID                       int                      `json:"id"`
	InnerID                  int                      `json:"inner_id"`
	IsLabeled                bool                     `json:"is_labeled"`
	LastCommentUpdatedAt     string                   `json:"last_comment_updated_at"`
	Meta                     map[string]interface{}   `json:"meta"`
	Overlap                  int                      `json:"overlap"`
	Predictions              []json.RawMessage        `json:"predictions"`
	PredictionsModelVersions json.RawMessage          `json:"predictions_model_versions"`
	PredictionsResults       json.RawMessage          `json:"predictions_results"`
	PredictionsScore         float64                  `json:"predictions_score"`
	Project                  int                      `json:"project"`
	ReviewTime               int                      `json:"review_time"`
	Reviewed                 bool                     `json:"reviewed"`
	Reviewers                []map[string]interface{} `json:"reviewers"`
	ReviewersCount           int                      `json:"reviewers_count"`
	ReviewsAccepted          int                      `json:"reviews_accepted"`
	ReviewsRejected          int                      `json:"reviews_rejected"`
	StorageFilename          string                   `json:"storage_filename"`
	TotalAnnotations         int                      `json:"total_annotations"`
	TotalPredictions         int                      `json:"total_predictions"`
	UnresolvedCommentCount   int                      `json:"unresolved_comment_count"`
	UpdatedAt                time.Time                `json:"updated_at"`
	UpdatedBy                []map[string]interface{} `json:"updated_by"`
}

// TasksListOptions represents query parameters that can be used to filter tasks
type TasksListOptions struct {
	ProjectID   int    // Filter by project ID
	Page        int    // Page number for pagination
	PageSize    int    // Number of items per page
	Ordering    string // Field to order by (e.g., "created_at", "-created_at" for descending)
	Query       string // Search query for filtering tasks
	IsLabeled   *bool  // Filter by labeled status
	IsReviewed  *bool  // Filter by review status
	GroundTruth *bool  // Filter by ground truth status
}

// ListTasks fetches the list of tasks from the Label Studio API
func (c *Client) ListTasks(options *TasksListOptions) (*TasksListResponse, error) {

	// Build URL with query parameters
	path := "/api/tasks/"
	if options != nil {
		queryParams := url.Values{}

		// Add all the possible filter parameters
		if options.ProjectID > 0 {
			queryParams.Add("project", fmt.Sprintf("%d", options.ProjectID))
		}
		if options.Page > 0 {
			queryParams.Add("page", fmt.Sprintf("%d", options.Page))
		}
		if options.PageSize > 0 {
			queryParams.Add("page_size", fmt.Sprintf("%d", options.PageSize))
		}
		if options.Ordering != "" {
			queryParams.Add("ordering", options.Ordering)
		}
		if options.Query != "" {
			queryParams.Add("query", options.Query)
		}
		if options.IsLabeled != nil {
			if *options.IsLabeled {
				queryParams.Add("is_labeled", "true")
			} else {
				queryParams.Add("is_labeled", "false")
			}
		}
		if options.IsReviewed != nil {
			if *options.IsReviewed {
				queryParams.Add("reviewed", "true")
			} else {
				queryParams.Add("reviewed", "false")
			}
		}
		if options.GroundTruth != nil {
			if *options.GroundTruth {
				queryParams.Add("ground_truth", "true")
			} else {
				queryParams.Add("ground_truth", "false")
			}
		}

		// Add query params to URL if we have any
		if len(queryParams) > 0 {
			path = fmt.Sprintf("%s?%s", path, queryParams.Encode())
		}
	}

	// Create request
	resp, err := c.makeRequest("GET", path, nil)
	if err != nil {
		return nil, fmt.Errorf("Failed to request %s: %v", path, err)
	}
	defer lint.LogOnErr(resp.Body.Close, "close response body")

	// Parse response
	var tasksResponse TasksListResponse
	if err := json.NewDecoder(resp.Body).Decode(&tasksResponse); err != nil {
		return nil, fmt.Errorf("failed to parse response: %w", err)
	}

	return &tasksResponse, nil
}
