package handlers

import (
	"net/http"

	"warpbox.dev/backend/libs/helpers"
	"warpbox.dev/backend/libs/web"
)

type apiDocsData struct {
	BaseURL             string
	UploadURL           string
	RequestSchemaURL    string
	ResponseSchemaURL   string
	ShareXExamplePath   string
	ShareXExampleURL    string
	ShareXDownloadURL   string
	ShareXFileFieldName string
	ShareXGroupWindow   string
}

func (a *App) APIDocs(w http.ResponseWriter, r *http.Request) {
	user, loggedIn := a.currentUser(r)
	actor := "anonymous"
	if loggedIn {
		actor = "user"
	}
	a.logger.Info("api docs viewed", withRequestLogAttrs(r,
		"source", "page",
		"severity", "user_activity",
		"code", 2501,
		"actor", actor,
		"user_id", user.ID,
	)...)
	a.renderPage(w, r, http.StatusOK, "api.html", web.PageData{
		Title:       "API documentation",
		Description: "Curl and ShareX upload examples for Warpbox.",
		Data: apiDocsData{
			BaseURL:             a.cfg.BaseURL,
			UploadURL:           a.cfg.BaseURL + "/api/v1/upload",
			RequestSchemaURL:    a.cfg.BaseURL + "/api/v1/schemas/upload-request.json",
			ResponseSchemaURL:   a.cfg.BaseURL + "/api/v1/schemas/upload-response.json",
			ShareXExamplePath:   "examples/sharex/warpbox-anonymous.sxcu",
			ShareXExampleURL:    a.cfg.BaseURL + "/api/v1/upload",
			ShareXDownloadURL:   a.cfg.BaseURL + "/api/v1/sharex/warpbox-anonymous.sxcu",
			ShareXFileFieldName: "sharex",
			ShareXGroupWindow:   uploadGroupWindow.String(),
		},
	})
}

func (a *App) ShareXAnonymousConfig(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Disposition", `attachment; filename="warpbox-anonymous.sxcu"`)
	helpers.WriteJSON(w, http.StatusOK, map[string]any{
		"Version":         "18.0.0",
		"Name":            "Warpbox Anonymous Upload",
		"DestinationType": "ImageUploader, TextUploader, FileUploader",
		"RequestMethod":   "POST",
		"RequestURL":      a.cfg.BaseURL + "/api/v1/upload",
		"Headers": map[string]string{
			"Accept": "application/json",
			// Group a multi-file selection (sent as back-to-back requests) into
			// one box. Remove this header for one box per file.
			uploadBatchHeader: "sharex",
		},
		"Body":         "MultipartFormData",
		"FileFormName": "sharex",
		"URL":          "{json:boxUrl}",
		"ThumbnailURL": "{json:thumbnailUrl}",
		"DeletionURL":  "{json:deleteUrl}",
		"ErrorMessage": "{json:error}",
	})
}

func (a *App) UploadRequestSchema(w http.ResponseWriter, r *http.Request) {
	helpers.WriteJSON(w, http.StatusOK, map[string]any{
		"$schema":     "https://json-schema.org/draft/2020-12/schema",
		"$id":         a.cfg.BaseURL + "/api/v1/schemas/upload-request.json",
		"title":       "Warpbox anonymous upload request",
		"description": "Multipart/form-data request accepted by POST /api/v1/upload. Send one or more files using either the file or sharex field.",
		"type":        "object",
		"properties": map[string]any{
			"file": map[string]any{
				"description": "One or more uploaded files. Use this field for curl and browser-style clients.",
				"type":        "array",
				"items":       map[string]any{"type": "string", "format": "binary"},
			},
			"sharex": map[string]any{
				"description": "One or more uploaded files. Use this field for ShareX custom uploader configs.",
				"type":        "array",
				"items":       map[string]any{"type": "string", "format": "binary"},
			},
			"max_days": map[string]any{
				"description": "Optional number of days before the box expires. Defaults to 7.",
				"type":        "integer",
				"minimum":     1,
			},
			"max_downloads": map[string]any{
				"description": "Optional maximum number of downloads before the box expires.",
				"type":        "integer",
				"minimum":     1,
			},
			"password": map[string]any{
				"description": "Optional box password.",
				"type":        "string",
			},
			"obfuscate_metadata": map[string]any{
				"description": "Optional checkbox-style value. When set with a password, hides file names/counts until unlock.",
				"type":        "string",
				"enum":        []string{"on"},
			},
		},
		"anyOf": []any{
			map[string]any{"required": []string{"file"}},
			map[string]any{"required": []string{"sharex"}},
		},
	})
}

func (a *App) UploadResponseSchema(w http.ResponseWriter, r *http.Request) {
	helpers.WriteJSON(w, http.StatusOK, map[string]any{
		"$schema":     "https://json-schema.org/draft/2020-12/schema",
		"$id":         a.cfg.BaseURL + "/api/v1/schemas/upload-response.json",
		"title":       "Warpbox anonymous upload JSON response",
		"description": "JSON response returned by POST /api/v1/upload when Accept: application/json is sent.",
		"type":        "object",
		"required":    []string{"boxId", "boxUrl", "zipUrl", "manageUrl", "deleteUrl", "expiresAt", "files"},
		"properties": map[string]any{
			"boxId":        map[string]any{"type": "string"},
			"boxUrl":       map[string]any{"type": "string", "format": "uri"},
			"zipUrl":       map[string]any{"type": "string", "format": "uri"},
			"thumbnailUrl": map[string]any{"type": "string", "format": "uri", "description": "Thumbnail of the most recently uploaded file (placeholder until generated)."},
			"manageUrl":    map[string]any{"type": "string", "format": "uri", "description": "Private bearer URL for managing/deleting this upload. Returned only at upload time."},
			"deleteUrl":    map[string]any{"type": "string", "format": "uri", "description": "Private bearer URL for deleting this upload (GET or POST). Returned only at upload time."},
			"expiresAt":    map[string]any{"type": "string", "format": "date-time"},
			"files": map[string]any{
				"type": "array",
				"items": map[string]any{
					"type":     "object",
					"required": []string{"id", "name", "size", "url"},
					"properties": map[string]any{
						"id":           map[string]any{"type": "string"},
						"name":         map[string]any{"type": "string"},
						"size":         map[string]any{"type": "string"},
						"url":          map[string]any{"type": "string", "format": "uri"},
						"thumbnailUrl": map[string]any{"type": "string", "format": "uri"},
					},
				},
			},
		},
	})
}
