package api

import (
	"encoding/json"
	"errors"
	"net/http"

	"github.com/go-chi/chi/v5"
	"github.com/jackc/pgx/v5/pgtype"

	"git.fabledsword.com/bvandeusen/minstrel/internal/auth"
	"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
	"git.fabledsword.com/bvandeusen/minstrel/internal/lidarrquarantine"
)

// quarantineView is the JSON shape returned by the user-facing endpoints
// that operate on a single quarantine row (POST /api/quarantine).
type quarantineView struct {
	UserID    string             `json:"user_id"`
	TrackID   string             `json:"track_id"`
	Reason    string             `json:"reason"`
	Notes     *string            `json:"notes,omitempty"`
	CreatedAt pgtype.Timestamptz `json:"created_at"`
}

func quarantineViewFrom(row dbq.LidarrQuarantine) quarantineView {
	return quarantineView{
		UserID:    uuidToString(row.UserID),
		TrackID:   uuidToString(row.TrackID),
		Reason:    string(row.Reason),
		Notes:     row.Notes,
		CreatedAt: row.CreatedAt,
	}
}

// flagBody is the JSON body for POST /api/quarantine. track_id is sent as
// the canonical hyphenated string the SPA already gets from /api/tracks/*.
type flagBody struct {
	TrackID string `json:"track_id"`
	Reason  string `json:"reason"`
	Notes   string `json:"notes"`
}

// handleFlag implements POST /api/quarantine. Upserts via Service.Flag.
func (h *handlers) handleFlag(w http.ResponseWriter, r *http.Request) {
	user, ok := auth.UserFromContext(r.Context())
	if !ok {
		writeErr(w, http.StatusUnauthorized, "unauthorized", "authentication required")
		return
	}
	var body flagBody
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeErr(w, http.StatusBadRequest, "bad_request", "invalid JSON body")
		return
	}
	trackID, ok := parseUUID(body.TrackID)
	if !ok {
		writeErr(w, http.StatusBadRequest, "bad_request", "invalid track id")
		return
	}
	row, err := h.lidarrQuarantine.Flag(r.Context(), user.ID, trackID, body.Reason, body.Notes)
	if err != nil {
		switch {
		case errors.Is(err, lidarrquarantine.ErrBadReason):
			writeErr(w, http.StatusBadRequest, "bad_reason", "invalid reason")
		case errors.Is(err, lidarrquarantine.ErrTrackNotFound):
			writeErr(w, http.StatusNotFound, "track_not_found", "track does not exist")
		default:
			h.logger.Error("api: flag", "err", err)
			writeErr(w, http.StatusInternalServerError, "server_error", "flag failed")
		}
		return
	}
	writeJSON(w, http.StatusCreated, quarantineViewFrom(row))
}

// handleUnflag implements DELETE /api/quarantine/{track_id}.
func (h *handlers) handleUnflag(w http.ResponseWriter, r *http.Request) {
	user, ok := auth.UserFromContext(r.Context())
	if !ok {
		writeErr(w, http.StatusUnauthorized, "unauthorized", "authentication required")
		return
	}
	id, ok := parseUUID(chi.URLParam(r, "track_id"))
	if !ok {
		writeErr(w, http.StatusBadRequest, "bad_request", "invalid track id")
		return
	}
	if err := h.lidarrQuarantine.Unflag(r.Context(), user.ID, id); err != nil {
		if errors.Is(err, lidarrquarantine.ErrQuarantineNotFound) {
			writeErr(w, http.StatusNotFound, "quarantine_not_found", "no quarantine for that track")
			return
		}
		h.logger.Error("api: unflag", "err", err)
		writeErr(w, http.StatusInternalServerError, "server_error", "unflag failed")
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// quarantineMineView is the per-row shape returned by GET /api/quarantine/mine,
// composed from the joined ListQuarantineForUserRow.
type quarantineMineView struct {
	TrackID           string             `json:"track_id"`
	Reason            string             `json:"reason"`
	Notes             *string            `json:"notes,omitempty"`
	CreatedAt         pgtype.Timestamptz `json:"created_at"`
	TrackTitle        string             `json:"track_title"`
	TrackDurationMs   int32              `json:"track_duration_ms"`
	AlbumID           string             `json:"album_id"`
	AlbumTitle        string             `json:"album_title"`
	AlbumCoverArtPath *string            `json:"album_cover_art_path,omitempty"`
	ArtistID          string             `json:"artist_id"`
	ArtistName        string             `json:"artist_name"`
}

// handleListMyQuarantine implements GET /api/quarantine/mine. Returns the
// caller's quarantines with track/album/artist detail.
func (h *handlers) handleListMyQuarantine(w http.ResponseWriter, r *http.Request) {
	user, ok := auth.UserFromContext(r.Context())
	if !ok {
		writeErr(w, http.StatusUnauthorized, "unauthorized", "authentication required")
		return
	}
	rows, err := h.lidarrQuarantine.ListMine(r.Context(), user.ID)
	if err != nil {
		h.logger.Error("api: list mine", "err", err)
		writeErr(w, http.StatusInternalServerError, "server_error", "list failed")
		return
	}
	out := make([]quarantineMineView, 0, len(rows))
	for _, row := range rows {
		out = append(out, quarantineMineView{
			TrackID:           uuidToString(row.LidarrQuarantine.TrackID),
			Reason:            string(row.LidarrQuarantine.Reason),
			Notes:             row.LidarrQuarantine.Notes,
			CreatedAt:         row.LidarrQuarantine.CreatedAt,
			TrackTitle:        row.TrackTitle,
			TrackDurationMs:   row.TrackDurationMs,
			AlbumID:           uuidToString(row.AlbumID),
			AlbumTitle:        row.AlbumTitle,
			AlbumCoverArtPath: row.AlbumCoverArtPath,
			ArtistID:          uuidToString(row.ArtistID),
			ArtistName:        row.ArtistName,
		})
	}
	writeJSON(w, http.StatusOK, out)
}
