package controller

import (
	"netidhub-saas-be/app/module/clients/request"
	"netidhub-saas-be/app/module/clients/service"
	"netidhub-saas-be/utils/paginator"

	"github.com/gofiber/fiber/v2"
	"github.com/google/uuid"
	"github.com/rs/zerolog"

	utilRes "netidhub-saas-be/utils/response"
	utilVal "netidhub-saas-be/utils/validator"
)

type clientsController struct {
	clientsService service.ClientsService
	Log            zerolog.Logger
}

type ClientsController interface {
	All(c *fiber.Ctx) error
	Show(c *fiber.Ctx) error
	Save(c *fiber.Ctx) error
	Update(c *fiber.Ctx) error
	Delete(c *fiber.Ctx) error

	// New hierarchy endpoints
	GetHierarchy(c *fiber.Ctx) error
	GetSubClients(c *fiber.Ctx) error
	CreateSubClient(c *fiber.Ctx) error
	MoveClient(c *fiber.Ctx) error
	GetClientStats(c *fiber.Ctx) error
	BulkCreateSubClients(c *fiber.Ctx) error

	// Client with user creation
	CreateClientWithUser(c *fiber.Ctx) error
}

func NewClientsController(clientsService service.ClientsService, log zerolog.Logger) ClientsController {
	return &clientsController{
		clientsService: clientsService,
		Log:            log,
	}
}

// All get all Clients
// @Summary      Get all Clients
// @Description  API for getting all Clients with hierarchy filtering
// @Tags         Clients
// @Security     Bearer
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        name query string false "Filter by client name"
// @Param        clientType query string false "Filter by client type (parent_client, sub_client, standalone)"
// @Param        parentClientId query string false "Filter by parent client ID"
// @Param        includeSubClients query boolean false "Include all descendants"
// @Param        onlyParentClients query boolean false "Only clients with children"
// @Param        onlyStandalone query boolean false "Only standalone clients"
// @Param        onlyRootClients query boolean false "Only root level clients"
// @Param        isActive query boolean false "Filter by active status"
// @Param        createdById query string false "Filter by creator ID"
// @Param        page query int false "Page number"
// @Param        limit query int false "Items per page"
// @Param        sort query string false "Sort field"
// @Param        sortBy query string false "Sort direction (asc, desc)"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients [get]
func (_i *clientsController) All(c *fiber.Ctx) error {
	paginate, err := paginator.Paginate(c)
	if err != nil {
		return err
	}

	reqContext := request.ClientsQueryRequestContext{
		Name:              c.Query("name"),
		ClientType:        c.Query("clientType"),
		ParentClientId:    c.Query("parentClientId"),
		IncludeSubClients: c.Query("includeSubClients"),
		OnlyParentClients: c.Query("onlyParentClients"),
		OnlyStandalone:    c.Query("onlyStandalone"),
		IsActive:          c.Query("isActive"),
		CreatedById:       c.Query("createdById"),
	}
	req := reqContext.ToParamRequest()
	req.Pagination = paginate

	// Get Authorization token from header
	authToken := c.Get("Authorization")
	_i.Log.Info().Str("authToken", authToken).Msg("")

	clientsData, paging, err := _i.clientsService.All(authToken, req)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Clients list successfully retrieved"},
		Data:     clientsData,
		Meta:     paging,
	})
}

// Show get one Clients
// @Summary      Get one Clients
// @Description  API for getting one Clients
// @Tags         Clients
// @Security     Bearer
// @Param        id path int true "Clients ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients/{id} [get]
func (_i *clientsController) Show(c *fiber.Ctx) error {
	idStr := c.Params("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		return err
	}

	clientsData, err := _i.clientsService.Show(id)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Clients successfully retrieved"},
		Data:     clientsData,
	})
}

// Save create Clients
// @Summary      Create Clients
// @Description  API for create Clients
// @Tags         Clients
// @Security     Bearer
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param 	     payload body request.ClientsCreateRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients [post]
func (_i *clientsController) Save(c *fiber.Ctx) error {
	req := new(request.ClientsCreateRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	authToken := c.Get("Authorization")
	dataResult, err := _i.clientsService.Save(*req, authToken)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Clients successfully created"},
		Data:     dataResult,
	})
}

// Update update Clients
// @Summary      update Clients
// @Description  API for update Clients
// @Tags         Clients
// @Security     Bearer
// @Param 	     payload body request.ClientsUpdateRequest true "Required payload"
// @Param        id path string true "Clients ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients/{id} [put]
func (_i *clientsController) Update(c *fiber.Ctx) error {
	idStr := c.Params("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		return err
	}

	req := new(request.ClientsUpdateRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	err = _i.clientsService.Update(id, *req)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Clients successfully updated"},
	})
}

// Delete delete Clients
// @Summary      delete Clients
// @Description  API for delete Clients
// @Tags         Clients
// @Security     Bearer
// @Param        id path string true "Clients ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients/{id} [delete]
func (_i *clientsController) Delete(c *fiber.Ctx) error {
	idStr := c.Params("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		return err
	}

	err = _i.clientsService.Delete(id)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Clients successfully deleted"},
	})
}

// =====================================================================
// NEW HIERARCHY ENDPOINTS
// =====================================================================

// GetHierarchy gets client tree structure
// @Summary      Get client hierarchy
// @Description  API for getting client tree structure
// @Tags         Clients
// @Security     Bearer
// @Param        id path string true "Client ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients/{id}/hierarchy [get]
func (_i *clientsController) GetHierarchy(c *fiber.Ctx) error {
	clientId, err := uuid.Parse(c.Params("id"))
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{"Invalid client ID"},
		})
	}

	hierarchy, err := _i.clientsService.GetHierarchy(clientId)
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{"Client not found"},
		})
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Client hierarchy successfully retrieved"},
		Data:     hierarchy,
	})
}

// GetSubClients gets direct children
// @Summary      Get sub-clients
// @Description  API for getting direct children of a client
// @Tags         Clients
// @Security     Bearer
// @Param        id path string true "Parent Client ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients/{id}/sub-clients [get]
func (_i *clientsController) GetSubClients(c *fiber.Ctx) error {
	parentId, err := uuid.Parse(c.Params("id"))
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{"Invalid parent client ID"},
		})
	}

	// For now, use GetAll with parent filter
	req := request.ClientsQueryRequest{
		ParentClientId: &parentId,
		Pagination:     &paginator.Pagination{Page: 1, Limit: 100},
	}

	subClients, _, err := _i.clientsService.All("", req)
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{"Failed to get sub-clients"},
		})
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Sub-clients successfully retrieved"},
		Data:     subClients,
	})
}

// CreateSubClient creates client under parent
// @Summary      Create sub-client
// @Description  API for creating a client under a parent
// @Tags         Clients
// @Security     Bearer
// @Param        id path string true "Parent Client ID"
// @Param 	     payload body request.ClientsCreateRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients/{id}/sub-clients [post]
func (_i *clientsController) CreateSubClient(c *fiber.Ctx) error {
	parentId, err := uuid.Parse(c.Params("id"))
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{"Invalid parent client ID"},
		})
	}

	req := new(request.ClientsCreateRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	client, err := _i.clientsService.CreateSubClient(parentId, *req)
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{err.Error()},
		})
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Sub-client successfully created"},
		Data:     client,
	})
}

// MoveClient moves client to different parent
// @Summary      Move client
// @Description  API for moving a client to different parent
// @Tags         Clients
// @Security     Bearer
// @Param        id path string true "Client ID"
// @Param        payload body request.MoveClientRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients/{id}/move [put]
func (_i *clientsController) MoveClient(c *fiber.Ctx) error {
	clientId, err := uuid.Parse(c.Params("id"))
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{"Invalid client ID"},
		})
	}

	req := new(request.MoveClientRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	err = _i.clientsService.MoveClient(clientId, *req)
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{err.Error()},
		})
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Client moved successfully"},
	})
}

// GetClientStats gets statistics
// @Summary      Get client statistics
// @Description  API for getting client statistics
// @Tags         Clients
// @Security     Bearer
// @Param        id path string true "Client ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients/{id}/stats [get]
func (_i *clientsController) GetClientStats(c *fiber.Ctx) error {
	clientId, err := uuid.Parse(c.Params("id"))
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{"Invalid client ID"},
		})
	}

	stats, err := _i.clientsService.GetClientStats(clientId)
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{"Client not found"},
		})
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Client statistics successfully retrieved"},
		Data:     stats,
	})
}

// BulkCreateSubClients creates multiple sub-clients
// @Summary      Bulk create sub-clients
// @Description  API for creating multiple sub-clients at once
// @Tags         Clients
// @Security     Bearer
// @Param        payload body request.BulkCreateSubClientsRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients/bulk-sub-clients [post]
func (_i *clientsController) BulkCreateSubClients(c *fiber.Ctx) error {
	req := new(request.BulkCreateSubClientsRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	result, err := _i.clientsService.BulkCreateSubClients(*req)
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{err.Error()},
		})
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Bulk operation completed"},
		Data:     result,
	})
}

// CreateClientWithUser creates a client and admin user in one request
// @Summary      Create client with admin user
// @Description  API for creating a client and its admin user in a single request (Public endpoint)
// @Tags         Clients
// @Param        payload body request.ClientWithUserCreateRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      500  {object}  response.InternalServerError
// @Router       /clients/with-user [post]
func (_i *clientsController) CreateClientWithUser(c *fiber.Ctx) error {
	req := new(request.ClientWithUserCreateRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	result, err := _i.clientsService.CreateClientWithUser(*req)
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{err.Error()},
		})
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{result.Message},
		Data:     result,
	})
}
