package repository

import (
	"fmt"
	"strings"
	"github.com/google/uuid"
	"github.com/rs/zerolog"
	"web-qudo-be/app/database"
	"web-qudo-be/app/database/entity"
	approvalWorkflowStepsEntity "web-qudo-be/app/database/entity"
	"web-qudo-be/app/module/approval_workflows/request"
	"web-qudo-be/utils/paginator"
)

type approvalWorkflowsRepository struct {
	DB  *database.Database
	Log zerolog.Logger
}

// ApprovalWorkflowsRepository define interface of IApprovalWorkflowsRepository
type ApprovalWorkflowsRepository interface {
	GetAll(clientId *uuid.UUID, req request.ApprovalWorkflowsQueryRequest) (workflows []*entity.ApprovalWorkflows, paging paginator.Pagination, err error)
	FindOne(clientId *uuid.UUID, id uint) (workflow *entity.ApprovalWorkflows, err error)
	FindDefault(clientId *uuid.UUID) (workflow *entity.ApprovalWorkflows, err error)
	GetDefault(clientId *uuid.UUID) (workflow *entity.ApprovalWorkflows, err error)
	GetWorkflowSteps(clientId *uuid.UUID, workflowId uint) (steps []*entity.ApprovalWorkflowSteps, err error)
	Create(clientId *uuid.UUID, workflow *entity.ApprovalWorkflows) (workflowReturn *entity.ApprovalWorkflows, err error)
	Update(clientId *uuid.UUID, id uint, workflow *entity.ApprovalWorkflows) (err error)
	Delete(clientId *uuid.UUID, id uint) (err error)
	SetDefault(clientId *uuid.UUID, id uint) (err error)
}

func NewApprovalWorkflowsRepository(db *database.Database, log zerolog.Logger) ApprovalWorkflowsRepository {
	return &approvalWorkflowsRepository{
		DB:  db,
		Log: log,
	}
}

// implement interface of IApprovalWorkflowsRepository
func (_i *approvalWorkflowsRepository) GetAll(clientId *uuid.UUID, req request.ApprovalWorkflowsQueryRequest) (workflows []*entity.ApprovalWorkflows, paging paginator.Pagination, err error) {
	var count int64

	query := _i.DB.DB.Model(&entity.ApprovalWorkflows{})

	// Add client filter
	if clientId != nil {
		query = query.Where("client_id = ?", clientId)
	}

	query = query.Where("approval_workflows.is_active = ?", true)

	if req.Name != nil && *req.Name != "" {
		name := strings.ToLower(*req.Name)
		query = query.Where("LOWER(approval_workflows.name) LIKE ?", "%"+strings.ToLower(name)+"%")
	}
	if req.Description != nil && *req.Description != "" {
		description := strings.ToLower(*req.Description)
		query = query.Where("LOWER(approval_workflows.description) LIKE ?", "%"+strings.ToLower(description)+"%")
	}
	if req.IsActive != nil {
		query = query.Where("approval_workflows.is_active = ?", req.IsActive)
	}
	if req.IsDefault != nil {
		query = query.Where("approval_workflows.is_default = ?", req.IsDefault)
	}
	query.Count(&count)

	if req.Pagination.SortBy != "" {
		direction := "ASC"
		if req.Pagination.Sort == "desc" {
			direction = "DESC"
		}
		query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
	} else {
		direction := "DESC"
		sortBy := "approval_workflows.is_default DESC, approval_workflows.created_at"
		query.Order(fmt.Sprintf("%s %s", sortBy, direction))
	}

	req.Pagination.Count = count
	req.Pagination = paginator.Paging(req.Pagination)

	err = query.Preload("Steps").Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&workflows).Error
	if err != nil {
		return
	}

	paging = *req.Pagination

	return
}

func (_i *approvalWorkflowsRepository) FindOne(clientId *uuid.UUID, id uint) (workflow *entity.ApprovalWorkflows, err error) {
	query := _i.DB.DB.Model(&entity.ApprovalWorkflows{})

	if clientId != nil {
		query = query.Where("client_id = ?", clientId)
	}

	query = query.Where("is_active = ?", true)
	query = query.Preload("Steps")

	err = query.First(&workflow, id).Error
	return workflow, err
}

func (_i *approvalWorkflowsRepository) FindDefault(clientId *uuid.UUID) (workflow *entity.ApprovalWorkflows, err error) {
	query := _i.DB.DB.Model(&entity.ApprovalWorkflows{})

	if clientId != nil {
		query = query.Where("client_id = ?", clientId)
	}

	query = query.Where("is_active = ? AND is_default = ?", true, true)
	query = query.Preload("Steps")

	err = query.First(&workflow).Error
	return workflow, err
}

func (_i *approvalWorkflowsRepository) Create(clientId *uuid.UUID, workflow *entity.ApprovalWorkflows) (workflowReturn *entity.ApprovalWorkflows, err error) {
	workflow.ClientId = clientId
	err = _i.DB.DB.Create(&workflow).Error
	return workflow, err
}

func (_i *approvalWorkflowsRepository) Update(clientId *uuid.UUID, id uint, workflow *entity.ApprovalWorkflows) (err error) {
	query := _i.DB.DB.Model(&entity.ApprovalWorkflows{})

	if clientId != nil {
		query = query.Where("client_id = ?", clientId)
	}

	err = query.Where("id = ?", id).Updates(workflow).Error
	return err
}

func (_i *approvalWorkflowsRepository) Delete(clientId *uuid.UUID, id uint) (err error) {
	query := _i.DB.DB.Model(&entity.ApprovalWorkflows{})

	if clientId != nil {
		query = query.Where("client_id = ?", clientId)
	}

	isActive := false
	err = query.Where("id = ?", id).Update("is_active", isActive).Error
	return err
}

func (_i *approvalWorkflowsRepository) SetDefault(clientId *uuid.UUID, id uint) (err error) {
	// First, unset all default workflows
	query := _i.DB.DB.Model(&entity.ApprovalWorkflows{})
	if clientId != nil {
		query = query.Where("client_id = ?", clientId)
	}
	err = query.Update("is_default", false).Error
	if err != nil {
		return err
	}

	// Then set the specified workflow as default
	query = _i.DB.DB.Model(&entity.ApprovalWorkflows{})
	if clientId != nil {
		query = query.Where("client_id = ?", clientId)
	}
	err = query.Where("id = ?", id).Update("is_default", true).Error
	return err
}

// GetDefault gets the default workflow for a client
func (_i *approvalWorkflowsRepository) GetDefault(clientId *uuid.UUID) (workflow *entity.ApprovalWorkflows, err error) {
	return _i.FindDefault(clientId)
}

// GetWorkflowSteps gets all steps for a specific workflow
func (_i *approvalWorkflowsRepository) GetWorkflowSteps(clientId *uuid.UUID, workflowId uint) (steps []*entity.ApprovalWorkflowSteps, err error) {
	query := _i.DB.DB.Model(&approvalWorkflowStepsEntity.ApprovalWorkflowSteps{})
	
	// Join with approval_workflows to check client_id
	query = query.Joins("JOIN approval_workflows ON approval_workflow_steps.workflow_id = approval_workflows.id")
	
	if clientId != nil {
		query = query.Where("approval_workflows.client_id = ?", clientId)
	}
	
	query = query.Where("approval_workflow_steps.workflow_id = ?", workflowId)
	query = query.Where("approval_workflows.is_active = ?", true)
	query = query.Order("approval_workflow_steps.step_order ASC")
	
	// Preload the RequiredUserLevel relation
	query = query.Preload("RequiredUserLevel")
	
	err = query.Find(&steps).Error
	return steps, err
}