package backend

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"path/filepath"
	"strings"
	"time"

	"github.com/libnovel/backend/internal/storage"
)

type importRequest struct {
	Title     string `json:"title"`
	FileName  string `json:"file_name"`
	FileType  string `json:"file_type"` // "pdf" or "epub"
	ObjectKey string `json:"object_key"` // MinIO path to uploaded file
}

type importResponse struct {
	TaskID   string         `json:"task_id"`
	Slug     string         `json:"slug"`
	Preview  *importPreview `json:"preview,omitempty"`
}

type importPreview struct {
	Chapters   int      `json:"chapters"`
	FirstLines []string `json:"first_lines"`
}

func (s *Server) handleAdminImport(w http.ResponseWriter, r *http.Request) {
	if s.deps.Producer == nil {
		jsonError(w, http.StatusServiceUnavailable, "task queue not configured")
		return
	}

	ct := r.Header.Get("Content-Type")
	var req importRequest
	var objectKey string

	if strings.HasPrefix(ct, "multipart/form-data") {
		if err := r.ParseMultipartForm(32 << 20); err != nil {
			jsonError(w, http.StatusBadRequest, "parse multipart: "+err.Error())
			return
		}
		req.Title = r.FormValue("title")
		req.FileName = r.FormValue("file_name")
		req.FileType = r.FormValue("file_type")
		analyzeOnly := r.FormValue("analyze") == "true"

		file, header, err := r.FormFile("file")
		if err != nil {
			jsonError(w, http.StatusBadRequest, "parse file: "+err.Error())
			return
		}
		defer file.Close()

		if req.FileName == "" {
			req.FileName = header.Filename
		}
		if req.FileType == "" {
			req.FileType = strings.TrimPrefix(filepath.Ext(header.Filename), ".")
		}

		data, err := io.ReadAll(file)
		if err != nil {
			jsonError(w, http.StatusBadRequest, "read file: "+err.Error())
			return
		}

		// Analyze only - just count chapters
		if analyzeOnly {
			preview := analyzeImportFile(data, req.FileType)
			writeJSON(w, 0, importResponse{
				Preview: preview,
			})
			return
		}

		// Upload to MinIO for actual import
		objectKey = fmt.Sprintf("imports/%d_%s", time.Now().Unix(), header.Filename)
		store, ok := s.deps.Producer.(*storage.Store)
		if !ok {
			jsonError(w, http.StatusInternalServerError, "storage not available")
			return
		}
		if err := store.PutImportFile(r.Context(), objectKey, data); err != nil {
			jsonError(w, http.StatusInternalServerError, "upload file: "+err.Error())
			return
		}
	} else {
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			jsonError(w, http.StatusBadRequest, "parse body: "+err.Error())
			return
		}
		objectKey = req.ObjectKey
	}

	if req.Title == "" {
		jsonError(w, http.StatusBadRequest, "title is required")
		return
	}
	if req.FileType != "pdf" && req.FileType != "epub" {
		jsonError(w, http.StatusBadRequest, "file_type must be 'pdf' or 'epub'")
		return
	}

	slug := strings.ToLower(strings.ReplaceAll(req.Title, " ", "-"))
	slug = strings.Map(func(r rune) rune {
		if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' {
			return r
		}
		return -1
	}, slug)

	taskID, err := s.deps.Producer.CreateImportTask(r.Context(), slug, req.Title, req.FileType, objectKey, "")
	if err != nil {
		jsonError(w, http.StatusInternalServerError, "create import task: "+err.Error())
		return
	}

	writeJSON(w, 0, importResponse{
		TaskID: taskID,
		Slug:   slug,
	})
}

// analyzeImportFile parses the file to count chapters and extract preview lines.
func analyzeImportFile(data []byte, fileType string) *importPreview {
	count, firstLines, err := storage.AnalyzeFile(data, fileType)
	if err != nil || count == 0 {
		// Fall back to rough size estimate so the UI still shows something
		count = estimateChapters(data, fileType)
	}
	return &importPreview{
		Chapters:   count,
		FirstLines: firstLines,
	}
}

func estimateChapters(data []byte, fileType string) int {
	// Rough estimate: ~100KB per chapter for PDF, ~50KB for EPUB
	size := len(data)
	if fileType == "pdf" {
		return size / 100000
	}
	return size / 50000
}

func (s *Server) handleAdminImportStatus(w http.ResponseWriter, r *http.Request) {
	taskID := r.PathValue("id")
	if taskID == "" {
		jsonError(w, http.StatusBadRequest, "task id required")
		return
	}

	task, ok, err := s.deps.TaskReader.GetImportTask(r.Context(), taskID)
	if err != nil {
		jsonError(w, http.StatusInternalServerError, "get task: "+err.Error())
		return
	}
	if !ok {
		jsonError(w, http.StatusNotFound, "task not found")
		return
	}

	writeJSON(w, 0, task)
}

func (s *Server) handleAdminImportList(w http.ResponseWriter, r *http.Request) {
	tasks, err := s.deps.TaskReader.ListImportTasks(r.Context())
	if err != nil {
		jsonError(w, http.StatusInternalServerError, "list tasks: "+err.Error())
		return
	}
	writeJSON(w, 0, map[string]any{"tasks": tasks})
}