package controller

import (
	"butterfliu/internal/service"
	"encoding/json"
	"io"
	"log"
	"net/http"
	"strconv"
	"sync"

	"github.com/go-chi/chi/v5"
)

type LibraryController struct {
	service    *service.LibraryService
	scanMutex  sync.Mutex
	isScanning bool
}

func NewLibraryController(service *service.LibraryService) *LibraryController {
	return &LibraryController{service: service}
}

func (c *LibraryController) GetAll(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	libraries, err := c.service.GetAll()
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	json.NewEncoder(w).Encode(libraries)
}

func (c *LibraryController) Create(w http.ResponseWriter, r *http.Request) {
	var library map[string]interface{}
	err := json.NewDecoder(r.Body).Decode(&library)
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	_, err = c.service.Create(library["name"].(string), library["path"].(string))
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	json.NewEncoder(w).Encode(map[string]string{"msg": "Add library successfully."})
}

func (c *LibraryController) UpdateName(w http.ResponseWriter, r *http.Request) {
	idParam := chi.URLParam(r, "id")
	name, _ := io.ReadAll(r.Body)
	defer r.Body.Close()
	id, err := strconv.Atoi(idParam)
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	err = c.service.UpdateName(id, string(name))
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	json.NewEncoder(w).Encode(map[string]string{"msg": "Updated library name."})
}

func (c *LibraryController) UpdatePath(w http.ResponseWriter, r *http.Request) {
	idParam := chi.URLParam(r, "id")
	path, _ := io.ReadAll(r.Body)
	defer r.Body.Close()
	id, err := strconv.Atoi(idParam)
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	err = c.service.UpdatePath(id, string(path))
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	json.NewEncoder(w).Encode(map[string]string{"msg": "Updated library path."})
}

func (c *LibraryController) Scan(w http.ResponseWriter, r *http.Request) {
	c.scanMutex.Lock()
	if c.isScanning {
		c.scanMutex.Unlock()
		json.NewEncoder(w).Encode(map[string]string{"error": "Another scan is already in progress"})
		return
	}
	c.isScanning = true
	c.scanMutex.Unlock()

	idParam := chi.URLParam(r, "id")
	id, err := strconv.Atoi(idParam)
	if err != nil {
		c.scanMutex.Lock()
		c.isScanning = false
		c.scanMutex.Unlock()
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}

	go func() {
		defer func() {
			c.scanMutex.Lock()
			c.isScanning = false
			c.scanMutex.Unlock()
		}()

		err := c.service.Scan(id)
		if err != nil {
			log.Printf("Scan failed: %v", err)
			return
		}

		log.Printf("Scan completed successfully for library %d", id)
	}()

	json.NewEncoder(w).Encode(map[string]string{"msg": "Library scan started."})
}

func (c *LibraryController) GetScanStatus(w http.ResponseWriter, r *http.Request) {
	c.scanMutex.Lock()
	scanning := c.isScanning
	c.scanMutex.Unlock()
	json.NewEncoder(w).Encode(map[string]bool{"scanning": scanning})
}

func (c *LibraryController) Delete(w http.ResponseWriter, r *http.Request) {
	idParam := chi.URLParam(r, "id")
	id, _ := strconv.Atoi(idParam)
	err := c.service.Delete(id)
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	json.NewEncoder(w).Encode(map[string]string{"msg": "Deleted library."})
}

func (c *LibraryController) GetSongs(w http.ResponseWriter, r *http.Request) {
	idParam := chi.URLParam(r, "id")
	id, err := strconv.Atoi(idParam)
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	songs, err := c.service.GetSongs(id)
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	json.NewEncoder(w).Encode(songs)
}

func (c *LibraryController) GetAllSongs(w http.ResponseWriter, r *http.Request) {
	songs, err := c.service.GetAllSongs()
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	json.NewEncoder(w).Encode(songs)
}

func (c *LibraryController) GetArtists(w http.ResponseWriter, r *http.Request) {
	artists, err := c.service.GetArtists()
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	json.NewEncoder(w).Encode(artists)
}

func (c *LibraryController) GetAlbums(w http.ResponseWriter, r *http.Request) {
	albums, err := c.service.GetAlbums()
	if err != nil {
		json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
		return
	}
	json.NewEncoder(w).Encode(albums)
}
