package server

import (
	"fmt"
	"net/http"
	d "playback-device-server/data"
	m "playback-device-server/management"

	"github.com/labstack/echo/v4"
)

type DeviceApiHandler struct {
	router        *echo.Echo
	deviceManager *m.DeviceManager
}

func (r *DeviceApiHandler) Initialize(authenticator *Authenticator) {
	r.router.Use(authenticator.Authenticate("/api/devices", []string{}))
	devicesApi := r.router.Group("/api/devices")
	//usersApi.POST("/register", r.handleRegister)
	//usersApi.POST("/deregister", r.handleDeregister)
	devicesApi.GET("/session/info", r.handleGetSessionInfo)
	devicesApi.PUT("/:id", r.handleUpdateConfig)
	devicesApi.GET("", r.handleGetDevices)
	devicesApi.POST("", r.handleCreateDevice)
	devicesApi.DELETE("/:id", r.handleDeleteDevice)

	r.router.Use(authenticator.Authenticate("/api/integrations", []string{"/api/integrations/register"}))
	integrationsApi := r.router.Group("/api/integrations")
	integrationsApi.POST("/register", r.handleIntegrationRegistration)
	integrationsApi.POST("", r.handleCreateIntegration)
	integrationsApi.GET("", r.handleGetIntegrations)
	integrationsApi.GET("/:id", r.handleGetIntegration)
	integrationsApi.DELETE("/:id", r.handleDeleteIntegration)
}

func (r *DeviceApiHandler) handleCreateIntegration(context echo.Context) error {
	code, error := r.deviceManager.GetRegistrationCode()

	if error != nil {
		SendError(500, context, fmt.Sprintf("failed to get registration code: %s", error))
		return error
	}

	response := struct {
		Code string `json:"code"`
	}{
		Code: code,
	}

	return context.JSON(200, response)
}

func (r *DeviceApiHandler) handleIntegrationRegistration(context echo.Context) error {
	var data struct {
		Name string `json:"name"`
		Code string `json:"code"`
	}
	error := context.Bind(&data)

	if error != nil {
		SendError(500, context, fmt.Sprintf("Failed to create integration: %s", error))
		return error
	}

	integration, error := r.deviceManager.CreateIntegration(data.Name, data.Code)

	if error != nil {
		SendError(400, context, fmt.Sprintf("Failed to create integration: %s", error))
		return error
	}

	integrationData := struct {
		ID    string `json:"id"`
		Name  string `json:"name"`
		Token string `json:"token"`
	}{
		ID:    integration.ID,
		Name:  integration.Name,
		Token: integration.Token,
	}

	thirdyDays := 30 * 24 * 60 * 60
	cookie := &http.Cookie{
		Name:     "token",
		Value:    integration.Token,
		Path:     "/",
		HttpOnly: true,
		MaxAge:   thirdyDays,
	}
	context.SetCookie(cookie)

	return context.JSON(200, integrationData)
}

func (r *DeviceApiHandler) handleGetIntegration(context echo.Context) error {
	id := context.Param("id")

	exists, err := r.deviceManager.IntegrationIdExists(id)
	if err != nil {
		SendError(500, context, fmt.Sprintf("Failed to get integration: %s", err))
		return err
	}
	if !exists {
		SendError(404, context, fmt.Sprintf("integration with id %s does not exist", id))
		return err
	}

	integration, err := r.deviceManager.GetIntegration(id)

	if err != nil {
		SendError(500, context, fmt.Sprintf("Failed to get integration: %s", err))
		return err
	}

	integrationData := struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	}{
		ID:   integration.ID,
		Name: integration.Name,
	}

	return context.JSON(200, integrationData)
}

func (r *DeviceApiHandler) handleGetIntegrations(context echo.Context) error {
	integrations, error := r.deviceManager.GetIntegrations()

	if error != nil {
		SendError(500, context, fmt.Sprintf("Failed to get integrations: %s", error))
		return error
	}

	return context.JSON(200, integrations)
}

func (r *DeviceApiHandler) handleDeleteIntegration(context echo.Context) error {
	id := context.Param("id")

	error := r.deviceManager.DeleteIntegration(id)

	if error != nil {
		SendError(500, context, fmt.Sprintf("Failed to delete integration: %s", error))
		return error
	}

	return context.JSON(200, "")
}

//func (r DeviceApiHandler) handleRegister(context echo.Context) error {
//	var registrationData struct {
//		Code string `json:"code"`
//	}
//
//	var errorResponse struct {
//		Error string `json:"error"`
//	}
//
//	error := context.Bind(&registrationData)
//
//	if error != nil {
//		log.Info().Msgf("failed to bind registration data: %s", error)
//		errorResponse.Error = fmt.Sprintf("%s", error)
//		context.JSON(400, errorResponse)
//		return error
//	}
//
//	token, error := r.deviceManger.Register(registrationData.Code)
//
//	if error != nil {
//		log.Info().Msgf("failed to register: %s", error)
//		errorResponse.Error = fmt.Sprintf("%s", error)
//		context.JSON(400, errorResponse)
//		return error
//	}
//
//	thirdyDays := 30 * 24 * 60 * 60
//
//	cookie := &http.Cookie{
//		Name:     "token",
//		Value:    token,
//		Path:     "/",
//		HttpOnly: true,
//		MaxAge:   thirdyDays,
//	}
//
//	context.SetCookie(cookie)
//
//	return context.JSON(200, "")
//}

//func (r UsersApiHandler) handleDeregister(context echo.Context) error {
//	r.removeTokenCookie(&context)
//	context.JSON(200, "")
//
//	authContext := context.(AuthContext)
//
//	session := authContext.Session
//	r.userManager.DeleteSession(session.Token)
//
//	return nil
//}

func (r DeviceApiHandler) handleGetSessionInfo(context echo.Context) error {
	//authContext := context.(AuthContext)
	//user := authContext.User

	response := struct {
		IntegrationID   string `json:"integration_id"`
		IntegrationName string `json:"integration_name"`
		DeviceID        string `json:"device_id"`
		DeviceName      string `json:"device_name"`
	}{
		IntegrationID:   "",
		IntegrationName: "",
		DeviceID:        "",
		DeviceName:      "",
	}

	return context.JSON(200, response)
}

func (r DeviceApiHandler) handleGetDevices(context echo.Context) error {
	users, error := r.deviceManager.GetDevices()
	if error != nil {
		SendError(500, context, fmt.Sprintf("failed to get device list: %s", error))
	}

	return context.JSON(200, users)
}

func (r DeviceApiHandler) handleCreateDevice(context echo.Context) error {
	var newDevice d.PlaybackDevice
	error := context.Bind(&newDevice)

	if error != nil {
		SendError(500, context, fmt.Sprintf("Failed to create playback device: %s", error))
		return error
	}

	id, error := r.deviceManager.CreateDevice(&newDevice)

	if error != nil {
		SendError(500, context, fmt.Sprintf("Failed to create playback device: %s", error))
		return error
	}

	newDevice.ID = id

	return context.JSON(200, newDevice)
}

func (r DeviceApiHandler) handleDeleteDevice(context echo.Context) error {
	id := context.Param("id")

	exists, error := r.deviceManager.DeviceIdExists(id)

	if error != nil {
		SendError(500, context, fmt.Sprintf("Failed to delete playbac device: %s", error))
		return error
	}

	if !exists {
		SendError(404, context, fmt.Sprintf("Failed to delete playback device: Could not find device id %s", id))
		return fmt.Errorf("not found")
	}

	error = r.deviceManager.DeleteDevice(id)
	if error != nil {
		SendError(500, context, fmt.Sprintf("Failed to delete playback device: %s", error))
		return error
	}

	return context.JSON(200, "")
}

func (r *DeviceApiHandler) handleUpdateConfig(context echo.Context) error {
	id := context.Param("id")

	var newDevice d.PlaybackDevice
	error := context.Bind(&newDevice)

	if error != nil {
		SendError(500, context, fmt.Sprintf("Failed to update device config: %s", error))
		return error
	}

	newDevice.ID = id
	error = r.deviceManager.UpdateDevice(&newDevice)

	if error != nil {
		SendError(500, context, fmt.Sprintf("Failed to update device config: %s", error))
		return error
	}

	return context.JSON(200, newDevice)
}

func (r *DeviceApiHandler) SetRouter(router *echo.Echo) {
	r.router = router
}

func (r *DeviceApiHandler) SetDeviceManager(deviceManager *m.DeviceManager) {
	r.deviceManager = deviceManager
}
