package handler

import (
	"encoding/json"
	"fmt"
	"log/slog"
	"net/http"
	"os"
	"strings"

	"mkiso-server/internal/service"
)

// writeJSON is a helper to write a JSON response.
func writeJSON(w http.ResponseWriter, status int, v interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(v)
}

// DownloadSingle handles GET /api/iso/download?accession_number=X
// Returns an ISO file as application/octet-stream.
func DownloadSingle(isoSvc *service.ISOService) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		acc := r.URL.Query().Get("accession_number")
		if acc == "" {
			writeJSON(w, http.StatusBadRequest, map[string]string{"error": "missing accession_number"})
			return
		}
		acc = strings.TrimSpace(acc)

		slog.Info("handling download single", "accession", acc)

		item, err := isoSvc.GenerateISO(r.Context(), acc)
		if err != nil {
			slog.Error("ISO generation failed", "accession", acc, "error", err)
			status := http.StatusInternalServerError
			msg := "ISO creation failed"
			if strings.Contains(err.Error(), "no DICOM data") {
				status = http.StatusNotFound
				msg = "no DICOM data for accession_number"
			}
			writeJSON(w, status, map[string]string{
				"error":  msg,
				"detail": err.Error(),
			})
			return
		}
		defer item.Cleanup()

		// Stream ISO file
		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, item.Filename))

		data, err := os.ReadFile(item.Path)
		if err != nil {
			slog.Error("read ISO file failed", "path", item.Path, "error", err)
			writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "failed to read ISO"})
			return
		}

		w.Write(data)
		slog.Info("ISO download completed", "accession", acc, "size", len(data))
	}
}

// DownloadMultiple handles GET /api/iso/download-multiple?accession_numbers=X,Y,Z
// Returns an ISO file as application/octet-stream.
func DownloadMultiple(isoSvc *service.ISOService) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		raw := r.URL.Query().Get("accession_numbers")
		if raw == "" {
			// Also check for "accession_number" with comma (backward compat)
			raw = r.URL.Query().Get("accession_number")
		}
		if raw == "" {
			writeJSON(w, http.StatusBadRequest, map[string]string{"error": "missing accession_numbers"})
			return
		}

		accs := parseAccessions(raw)
		if len(accs) == 0 {
			writeJSON(w, http.StatusBadRequest, map[string]string{"error": "empty accession_number list"})
			return
		}

		slog.Info("handling download multiple", "accessions", accs)

		item, err := isoSvc.GenerateISOMultiple(r.Context(), accs)
		if err != nil {
			slog.Error("ISO generation failed", "accessions", accs, "error", err)
			status := http.StatusInternalServerError
			msg := "ISO creation failed"
			if strings.Contains(err.Error(), "no DICOM data") {
				status = http.StatusNotFound
				msg = "no DICOM data for accession_numbers"
			}
			writeJSON(w, status, map[string]string{
				"error":  msg,
				"detail": err.Error(),
			})
			return
		}
		defer item.Cleanup()

		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, item.Filename))

		data, err := os.ReadFile(item.Path)
		if err != nil {
			slog.Error("read ISO file failed", "path", item.Path, "error", err)
			writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "failed to read ISO"})
			return
		}

		w.Write(data)
		slog.Info("ISO download completed (multiple)", "accessions", accs, "size", len(data))
	}
}

// parseAccessions parses a comma-separated list of accession numbers,
// trimming whitespace and filtering empty entries.
func parseAccessions(raw string) []string {
	parts := strings.Split(raw, ",")
	var result []string
	for _, p := range parts {
		p = strings.TrimSpace(p)
		if p != "" {
			result = append(result, p)
		}
	}
	return result
}
