package main

import (
	"bytes"
	"io"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/labstack/echo/v5"
	"github.com/pocketbase/pocketbase"
	"github.com/pocketbase/pocketbase/apis"
	"github.com/pocketbase/pocketbase/core"
)

func main() {
	app := pocketbase.New()

	app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
		_, err := e.Router.AddRoute(echo.Route{
			Method: http.MethodGet,
			Path:   "/cors",
			Handler: func(c echo.Context) error {
				return corsProxyHandler(c)
			},
			Middlewares: []echo.MiddlewareFunc{
				apis.ActivityLogger(app),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})

	app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
		// add new "GET /hello" route to the app router (echo)
		e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS("./pb_public"), false))
		return nil
	})

	app.OnFileDownloadRequest().Add(func(e *core.FileDownloadEvent) error {

		if strings.HasSuffix(e.ServedPath, ".html") {
			e.HttpContext.Response().Header().Set("Content-Disposition", "inline")
			e.HttpContext.Response().Header().Set("Content-Security-Policy", "")
		}
		log.Println(e.ServedPath)
		log.Println(e.HttpContext)
		return nil
	})

	if err := app.Start(); err != nil {
		log.Fatal(err)
	}
}

func corsProxyHandler(c echo.Context) error {
	// Get the target URL from the request query string
	url := c.QueryParam("url")
	if url == "" {
		return c.JSON(http.StatusBadRequest, "url param is required")
	}

	// Fetch the resource from the target URL
	resp, err := http.Get(url)
	if err != nil {
		return c.JSON(http.StatusInternalServerError, "Failed to fetch the URL")
	}
	defer resp.Body.Close()

	// If the content is a .m3u8 file, rewrite the URLs
	if strings.HasSuffix(url, ".m3u8") {
		bodyBytes, err := io.ReadAll(resp.Body)
		if err != nil {
			return c.JSON(http.StatusInternalServerError, "Failed to read response body")
		}

		proxyBaseURL := c.Scheme() + "://" + c.Request().Host + c.Path() + "?url=" + url[:strings.LastIndex(url, "/")+1]

		// Rewrite the URLs in the .m3u8 file
		lines := strings.Split(string(bodyBytes), "\n")
		for i, line := range lines {
			if strings.HasSuffix(line, ".ts") {
				lines[i] = proxyBaseURL + line
			}
		}
		modifiedContent := strings.Join(lines, "\n")

		// Write the modified content to the response
		c.Response().Header().Set("Content-Type", resp.Header.Get("Content-Type"))
		c.Response().WriteHeader(resp.StatusCode)
		_, err = io.Copy(c.Response().Writer, bytes.NewReader([]byte(modifiedContent)))
		if err != nil {
			return c.JSON(http.StatusInternalServerError, "Failed to copy modified response body")
		}

		return nil
	}

	// Copy the headers from the fetched response to the proxy response
	for key, values := range resp.Header {
		for _, value := range values {
			c.Response().Header().Add(key, value)
		}
	}

	// Copy the status code from the fetched response to the proxy response
	c.Response().WriteHeader(resp.StatusCode)

	// Copy the body from the fetched response to the proxy response
	_, err = io.Copy(c.Response().Writer, resp.Body)
	if err != nil {
		return c.JSON(http.StatusInternalServerError, "Failed to copy response body")
	}

	return nil
}
