package handlersHTTP

import (
	"encoding/json"
	"fmt"
	"git.insit.tech/psa/rtsp_reader-writer/reader/internal/config"
	"git.insit.tech/psa/rtsp_reader-writer/reader/internal/processor"
	"git.insit.tech/psa/rtsp_reader-writer/reader/internal/web/handlers"
	"git.insit.tech/psa/rtsp_reader-writer/writer/pkg/storage"
	"github.com/gofiber/fiber/v2"
	"log"
	"net/http"
	"os"
)

// Download processes Download request.
func Download(w http.ResponseWriter, r *http.Request) {
	log.Printf("new download request: %+v\n", r)

	downloadRequest := handlers.VideoRequest{}

	err := json.NewDecoder(r.Body).Decode(&downloadRequest)
	if err != nil {
		log.Printf("json decode error: %v\n", err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	pathFileNameRes, err := processor.Process(downloadRequest.Date, downloadRequest.StartTime, downloadRequest.EndTime)
	if err != nil {
		log.Printf("process error: %v\n", err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	w.Header().Set("Content-Type", "video/mp4")
	// Разрешаем частичную загрузку (поддержка перемотки)
	w.Header().Set("Accept-Ranges", "bytes")

	http.ServeFile(w, r, pathFileNameRes)
}

// HLS processes Download request.
func HLS(w http.ResponseWriter, r *http.Request) {
	log.Printf("new hls request: %+v\n", r)

	path := "/home/psa/GoRepository/data/1280x720/"

	w.Header().Set("Access-Control-Allow-Origin", "*")
	http.StripPrefix("/hls", http.FileServer(http.Dir(path))).ServeHTTP(w, r)
}

// ConfigVodsHandler returns configuration of the requested VOD location.
//
// This method allows to get a single VOD location.
func ConfigVodsHandler(c *fiber.Ctx) error {
	// Read camera id.
	id := c.Params("id")

	// Get resolutions.
	resolutions, err := storage.GetResolutions(id)
	if err != nil {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	// Calculate response fields.

	// Create path to first resolution.
	resDir := fmt.Sprintf("%s/%s/%s", config.DirData, id, resolutions[0])

	// Read directory.
	entries, err := os.ReadDir(resDir)
	if err != nil {
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	// Check if a folder has files that was not created or modified for last 5 minutes.
	disabled, err := handlers.Inactive5Minutes(entries)
	if err != nil {
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	// Calculate the difference between first existing rec file and the last one in milliseconds.
	segmentDuration, err := handlers.RecDurationMilliseconds(entries)
	if err != nil {
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	// Prepare the Response.
	VodsRes := handlers.ConfigVodsResponse{
		Prefix:          id,
		AutoMbr:         false, // Always false. Temporary.
		Disabled:        disabled,
		SegmentDuration: segmentDuration,
		AddAudioOnly:    false, // Always false. Temporary.
		Provider:        "Insit",
	}

	// Write header and code response.
	return c.JSON(VodsRes)
}

// DelVodsHandler delete archive of the requested VOD location.
//
// This method delete a single VOD location by its prefix.
func DelVodsHandler(c *fiber.Ctx) error {
	// Read camera id.
	id := c.Params("id")

	err := os.Remove(fmt.Sprintf("%s/%s", config.DirData, id))
	if err != nil {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	return c.SendStatus(fiber.StatusNoContent)
}

// ListFilesVodsHandler returns the list of all files and folders in archive for a specific VOD location.
//
// This method allows to get the list of all files and folders for a specific VOD location.
func ListFilesVodsHandler(c *fiber.Ctx) error {
	// Read camera id.
	id := c.Params("id")

	// Create map for response.
	files := make(map[string][]string)

	// Get resolutions.
	resolutions, err := storage.GetResolutions(id)
	if err != nil {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	for _, resolution := range resolutions {
		// Create path to the resolutions.
		resDir := fmt.Sprintf("%s/%s/%s", config.DirData, id, resolution)

		// Read directory.
		entries, err := os.ReadDir(resDir)
		if err != nil {
			return c.SendStatus(fiber.StatusInternalServerError)
		}

		// Create slice for files in folders.
		filesInFolder := make([]string, 0)

		// Add all files to the slice with files.
		for _, entry := range entries {
			filesInFolder = append(filesInFolder, entry.Name())
		}

		// Add resolution and all files to the response map.
		files[resolution] = filesInFolder
	}

	// Prepare the Response.
	vodsRes := handlers.ListVodsResponse{
		EstimatedCount: len(files),
		Files:          files,
	}

	// Write header and code response.
	return c.JSON(vodsRes)
}

// SingleVodsHandler returns a specific file in archive for a specific resolution and VOD location.
//
// This method allows to get a single VOD file.
func SingleVodsHandler(c *fiber.Ctx) error {
	// Read camera id, res, filename.
	id := c.Params("id")
	res := c.Params("res")
	file := c.Params("file")

	// Calculate file size in bytes.
	FileBytes, err := storage.FileBytes(id, res, file)
	if err != nil {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	dur, tracks, err := storage.GetDurAndTracks(id, res, file)
	if err != nil {
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	media := handlers.MediaSingleVodsResponse{
		Tracks:   tracks,
		Duration: dur,
		Provider: "Insit",
		Title:    id,
	}

	// Prepare the Response.
	vodsRes := handlers.SingleVodsResponse{
		Name:      file,
		Prefix:    id,
		Url:       c.OriginalURL(),
		Folder:    res,
		Bytes:     FileBytes,
		MediaInfo: media,
	}

	// Write header and code response.
	return c.JSON(vodsRes)
}

// DelSingleVodsHandler deletes a VOD file by its name.
//
// This method deletes a VOD file by its name.
func DelSingleVodsHandler(c *fiber.Ctx) error {
	// Read camera id, res, filename.
	id := c.Params("id")
	res := c.Params("res")
	file := c.Params("file")

	if err := os.Remove(fmt.Sprintf("%s/%s/%s/%s", config.DirData, id, res, file)); err != nil {
		return c.SendStatus(fiber.StatusNotFound)
	}

	return c.SendStatus(fiber.StatusNoContent)
}

/*
// FileHandler обработчик для работы с файлами
func FileHandler(c *fiber.Ctx) error {
	// Если запрос содержит session_id - получаем файл
	sessionData := c.Locals(ContextKeySession).(*SessionData)

	// Логика получения файла
	fileContent, err := getFileContent(sessionData.FileName)
	if err != nil {
		return c.Status(fiber.StatusNotFound).SendString("File not found")
	}

	return c.Send(fileContent)
}
*/
