package controller

import (
	"math"
	"strconv"
	"strings"

	"gitlab.com/mbugroup/lti-api.git/internal/modules/finance/transactions/dto"
	service "gitlab.com/mbugroup/lti-api.git/internal/modules/finance/transactions/services"
	validation "gitlab.com/mbugroup/lti-api.git/internal/modules/finance/transactions/validations"
	"gitlab.com/mbugroup/lti-api.git/internal/response"

	"github.com/gofiber/fiber/v2"
)

type TransactionController struct {
	TransactionService service.TransactionService
}

func NewTransactionController(transactionService service.TransactionService) *TransactionController {
	return &TransactionController{
		TransactionService: transactionService,
	}
}

func (u *TransactionController) GetAll(c *fiber.Ctx) error {
	parseUintListParam := func(key string) ([]uint, error) {
		raw := strings.TrimSpace(c.Query(key, ""))
		if raw == "" {
			return nil, nil
		}
		parts := strings.Split(raw, ",")
		ids := make([]uint, 0, len(parts))
		for _, part := range parts {
			trimmed := strings.TrimSpace(part)
			if trimmed == "" {
				return nil, strconv.ErrSyntax
			}
			parsed, err := strconv.ParseUint(trimmed, 10, 64)
			if err != nil {
				return nil, err
			}
			if parsed == 0 {
				continue
			}
			ids = append(ids, uint(parsed))
		}
		if len(ids) == 0 {
			return nil, nil
		}
		return ids, nil
	}

	parseStringListParam := func(key string) ([]string, error) {
		raw := strings.TrimSpace(c.Query(key, ""))
		if raw == "" {
			return nil, nil
		}
		parts := strings.Split(raw, ",")
		values := make([]string, 0, len(parts))
		for _, part := range parts {
			trimmed := strings.TrimSpace(part)
			if trimmed == "" {
				return nil, strconv.ErrSyntax
			}
			values = append(values, trimmed)
		}
		if len(values) == 0 {
			return nil, nil
		}
		return values, nil
	}

	bankIDs, err := parseUintListParam("bank_ids")
	if err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid bank_ids")
	}
	customerIDs, err := parseUintListParam("customer_ids")
	if err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid customer_ids")
	}
	supplierIDs, err := parseUintListParam("supplier_ids")
	if err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid supplier_ids")
	}
	transactionTypes, err := parseStringListParam("transaction_types")
	if err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction_types")
	}

	query := &validation.Query{
		Page:             c.QueryInt("page", 1),
		Limit:            c.QueryInt("limit", 10),
		Search:           c.Query("search", ""),
		TransactionTypes: transactionTypes,
		BankIDs:          bankIDs,
		CustomerIDs:      customerIDs,
		SupplierIDs:      supplierIDs,
		SortDate:         c.Query("sort_date", ""),
		StartDate:        c.Query("start_date", ""),
		EndDate:          c.Query("end_date", ""),
	}

	if query.Page < 1 || query.Limit < 1 {
		return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
	}

	result, totalResults, err := u.TransactionService.GetAll(c, query)
	if err != nil {
		return err
	}

	return c.Status(fiber.StatusOK).
		JSON(response.SuccessWithPaginate[dto.TransactionListDTO]{
			Code:    fiber.StatusOK,
			Status:  "success",
			Message: "Get all transactions successfully",
			Meta: response.Meta{
				Page:         query.Page,
				Limit:        query.Limit,
				TotalPages:   int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
				TotalResults: totalResults,
			},
			Data: dto.ToTransactionListDTOs(result),
		})
}

func (u *TransactionController) GetOne(c *fiber.Ctx) error {
	param := c.Params("id")

	id, err := strconv.Atoi(param)
	if err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
	}

	result, err := u.TransactionService.GetOne(c, uint(id))
	if err != nil {
		return err
	}

	return c.Status(fiber.StatusOK).
		JSON(response.Success{
			Code:    fiber.StatusOK,
			Status:  "success",
			Message: "Get transaction successfully",
			Data:    dto.ToTransactionListDTO(*result),
		})
}

func (u *TransactionController) DeleteOne(c *fiber.Ctx) error {
	param := c.Params("id")

	id, err := strconv.Atoi(param)
	if err != nil {
		return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
	}

	if err := u.TransactionService.DeleteOne(c, uint(id)); err != nil {
		return err
	}

	return c.Status(fiber.StatusOK).
		JSON(response.Common{
			Code:    fiber.StatusOK,
			Status:  "success",
			Message: "Delete transaction successfully",
		})
}
