package repository

import (
	"fmt"
	"time"
	"web-qudo-be/app/database"
	"web-qudo-be/app/database/entity"
	"web-qudo-be/app/module/article_approval_flows/request"
	"web-qudo-be/utils/paginator"

	"github.com/google/uuid"
	"github.com/rs/zerolog"
)

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

// ArticleApprovalFlowsRepository define interface of IArticleApprovalFlowsRepository
type ArticleApprovalFlowsRepository interface {
	// Basic CRUD
	GetAll(clientId *uuid.UUID, req request.ArticleApprovalFlowsQueryRequest) (flows []*entity.ArticleApprovalFlows, paging paginator.Pagination, err error)
	FindOne(clientId *uuid.UUID, id uint) (flow *entity.ArticleApprovalFlows, err error)
	FindActiveByArticleId(articleId uint) (flow *entity.ArticleApprovalFlows, err error)
	FindByArticleId(clientId *uuid.UUID, articleId uint) (flow *entity.ArticleApprovalFlows, err error)
	Create(clientId *uuid.UUID, flow *entity.ArticleApprovalFlows) (flowReturn *entity.ArticleApprovalFlows, err error)
	Update(id uint, flow *entity.ArticleApprovalFlows) (err error)
	Delete(clientId *uuid.UUID, id uint) (err error)

	// Approval Queue Methods
	GetPendingApprovals(clientId *uuid.UUID, userLevelId uint, page, limit int, filters map[string]interface{}) (flows []*entity.ArticleApprovalFlows, paging paginator.Pagination, err error)
	GetPendingApprovalsByUserLevel(clientId *uuid.UUID, userLevelId uint, page, limit int) (flows []*entity.ArticleApprovalFlows, paging paginator.Pagination, err error)
	GetMyApprovalQueue(clientId *uuid.UUID, userLevelId uint, page, limit int, includePreview bool, urgentOnly bool) (flows []*entity.ArticleApprovalFlows, paging paginator.Pagination, err error)

	// Statistics Methods
	GetPendingCountByLevel(clientId *uuid.UUID, userLevelId uint) (count int64, err error)
	GetOverdueCountByLevel(clientId *uuid.UUID, userLevelId uint) (count int64, err error)
	GetApprovedCountByPeriod(clientId *uuid.UUID, userLevelId uint, startDate, endDate time.Time) (count int64, err error)
	GetRejectedCountByPeriod(clientId *uuid.UUID, userLevelId uint, startDate, endDate time.Time) (count int64, err error)
	GetRevisionRequestCountByPeriod(clientId *uuid.UUID, userLevelId uint, startDate, endDate time.Time) (count int64, err error)

	// Workload Methods
	GetLevelWorkload(clientId *uuid.UUID, userLevelId uint) (workload map[string]interface{}, err error)
	GetTeamWorkloadComparison(clientId *uuid.UUID, userLevelId uint) (comparison []map[string]interface{}, err error)
	GetWorkflowBottlenecks(clientId *uuid.UUID) (bottlenecks []map[string]interface{}, err error)
}

func NewArticleApprovalFlowsRepository(db *database.Database, log zerolog.Logger) ArticleApprovalFlowsRepository {
	return &articleApprovalFlowsRepository{
		DB:  db,
		Log: log,
	}
}

// Basic CRUD implementations
func (_i *articleApprovalFlowsRepository) GetAll(clientId *uuid.UUID, req request.ArticleApprovalFlowsQueryRequest) (flows []*entity.ArticleApprovalFlows, paging paginator.Pagination, err error) {
	var count int64

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

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

	// Apply filters from request
	if req.ArticleId != nil && *req.ArticleId > 0 {
		query = query.Where("article_id = ?", *req.ArticleId)
	}

	if req.StatusId != nil && *req.StatusId > 0 {
		query = query.Where("status_id = ?", *req.StatusId)
	}

	if req.SubmittedBy != nil && *req.SubmittedBy > 0 {
		query = query.Where("submitted_by_id = ?", *req.SubmittedBy)
	}

	if req.CurrentStep != nil && *req.CurrentStep > 0 {
		query = query.Where("current_step = ?", *req.CurrentStep)
	}

	if req.DateFrom != nil {
		query = query.Where("submitted_at >= ?", *req.DateFrom)
	}

	if req.WorkflowId != nil {
		query = query.Where("workflow_id = ?", *req.WorkflowId)
	}

	if req.DateTo != nil {
		query = query.Where("submitted_at <= ?", *req.DateTo)
	}

	// Preload related data
	query = query.Preload("Article").Preload("Workflow").Preload("SubmittedBy").Preload("StepLogs")
	query = query.Order("submitted_at DESC")

	err = query.Count(&count).Error
	if err != nil {
		return nil, paginator.Pagination{}, err
	}

	// Apply pagination
	page := req.Pagination.Page
	limit := req.Pagination.Limit
	if page <= 0 {
		page = 1
	}
	if limit <= 0 {
		limit = 10
	}

	offset := (page - 1) * limit
	err = query.Offset(offset).Limit(limit).Find(&flows).Error
	if err != nil {
		return nil, paginator.Pagination{}, err
	}

	paging = paginator.Pagination{
		Page:      page,
		Limit:     limit,
		Count:     int64(count),
		TotalPage: int((count + int64(limit) - 1) / int64(limit)),
	}

	return flows, paging, nil
}
func (_i *articleApprovalFlowsRepository) FindOne(clientId *uuid.UUID, id uint) (flow *entity.ArticleApprovalFlows, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalFlows{})

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

	query = query.Preload("Article").Preload("Workflow").Preload("SubmittedBy").Preload("StepLogs")

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

func (_i *articleApprovalFlowsRepository) FindActiveByArticleId(articleId uint) (flow *entity.ArticleApprovalFlows, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalFlows{})
	query = query.Where("article_id = ? AND status_id IN (1, 4)", articleId) // pending or revision_requested
	query = query.Preload("Article").Preload("Workflow").Preload("SubmittedBy").Preload("StepLogs")

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

func (_i *articleApprovalFlowsRepository) Create(clientId *uuid.UUID, flow *entity.ArticleApprovalFlows) (flowReturn *entity.ArticleApprovalFlows, err error) {
	flow.ClientId = clientId
	err = _i.DB.DB.Create(&flow).Error
	return flow, err
}

func (_i *articleApprovalFlowsRepository) Update(id uint, flow *entity.ArticleApprovalFlows) (err error) {
	err = _i.DB.DB.Model(&entity.ArticleApprovalFlows{}).Where("id = ?", id).Updates(flow).Error
	return err
}

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

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

	err = query.Delete(&entity.ArticleApprovalFlows{}, id).Error
	return err
}

// Approval Queue Methods
func (_i *articleApprovalFlowsRepository) GetPendingApprovals(clientId *uuid.UUID, userLevelId uint, page, limit int, filters map[string]interface{}) (flows []*entity.ArticleApprovalFlows, paging paginator.Pagination, err error) {
	var count int64

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

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

	// Join with workflow steps to find current step requirements
	query = query.Joins("JOIN approval_workflows ON article_approval_flows.workflow_id = approval_workflows.id")
	query = query.Joins("JOIN approval_workflow_steps ON approval_workflows.id = approval_workflow_steps.workflow_id AND article_approval_flows.current_step = approval_workflow_steps.step_order")
	query = query.Where("approval_workflow_steps.required_user_level_id = ?", userLevelId)
	query = query.Where("article_approval_flows.status_id IN (1, 4)") // pending or revision_requested
	query = query.Where("article_approval_flows.current_step > 0")    // exclude completed flows (current_step = 0)

	// Debug logging
	_i.Log.Info().
		Interface("clientId", clientId).
		Uint("userLevelId", userLevelId).
		Msg("Getting pending approvals for user level")

	// Apply filters
	if categoryId, ok := filters["category_id"]; ok {
		query = query.Joins("JOIN articles ON article_approval_flows.article_id = articles.id")
		query = query.Where("articles.category_id = ?", categoryId)
	}

	if typeId, ok := filters["type_id"]; ok {
		query = query.Joins("JOIN articles ON article_approval_flows.article_id = articles.id")
		query = query.Where("articles.type_id = ?", typeId)
	}

	if search, ok := filters["search"]; ok {
		query = query.Joins("JOIN articles ON article_approval_flows.article_id = articles.id")
		query = query.Where("articles.title ILIKE ? OR articles.description ILIKE ?", fmt.Sprintf("%%%s%%", search), fmt.Sprintf("%%%s%%", search))
	}

	query = query.Preload("Article").Preload("Workflow").Preload("SubmittedBy").Preload("StepLogs")
	query = query.Order("article_approval_flows.submitted_at ASC")

	err = query.Count(&count).Error
	if err != nil {
		return nil, paginator.Pagination{}, err
	}

	// Debug logging
	_i.Log.Info().
		Int64("count", count).
		Msg("Found pending approvals count")

	offset := (page - 1) * limit
	err = query.Offset(offset).Limit(limit).Find(&flows).Error
	if err != nil {
		return nil, paginator.Pagination{}, err
	}

	// Debug logging
	_i.Log.Info().
		Int("flowsCount", len(flows)).
		Msg("Retrieved flows from database")

	paging = paginator.Pagination{
		Page:      page,
		Limit:     limit,
		Count:     int64(count),
		TotalPage: int((count + int64(limit) - 1) / int64(limit)),
	}

	return flows, paging, nil
}

func (_i *articleApprovalFlowsRepository) GetMyApprovalQueue(clientId *uuid.UUID, userLevelId uint, page, limit int, includePreview bool, urgentOnly bool) (flows []*entity.ArticleApprovalFlows, paging paginator.Pagination, err error) {
	filters := make(map[string]interface{})
	if urgentOnly {
		// Add logic for urgent articles (e.g., submitted more than 24 hours ago)
		filters["urgent"] = true
	}

	return _i.GetPendingApprovals(clientId, userLevelId, page, limit, filters)
}

// Statistics Methods
func (_i *articleApprovalFlowsRepository) GetPendingCountByLevel(clientId *uuid.UUID, userLevelId uint) (count int64, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalFlows{})

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

	query = query.Joins("JOIN approval_workflows ON article_approval_flows.workflow_id = approval_workflows.id")
	query = query.Joins("JOIN approval_workflow_steps ON approval_workflows.id = approval_workflow_steps.workflow_id AND article_approval_flows.current_step = approval_workflow_steps.step_order")
	query = query.Where("approval_workflow_steps.required_user_level_id = ?", userLevelId)
	query = query.Where("article_approval_flows.status_id IN (1, 4)") // pending or revision_requested

	err = query.Count(&count).Error
	return count, err
}

func (_i *articleApprovalFlowsRepository) GetOverdueCountByLevel(clientId *uuid.UUID, userLevelId uint) (count int64, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalFlows{})

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

	query = query.Joins("JOIN approval_workflows ON article_approval_flows.workflow_id = approval_workflows.id")
	query = query.Joins("JOIN approval_workflow_steps ON approval_workflows.id = approval_workflow_steps.workflow_id AND article_approval_flows.current_step = approval_workflow_steps.step_order")
	query = query.Where("approval_workflow_steps.required_user_level_id = ?", userLevelId)
	query = query.Where("article_approval_flows.status_id IN (1, 4)")                             // pending or revision_requested
	query = query.Where("article_approval_flows.submitted_at < ?", time.Now().Add(-24*time.Hour)) // overdue after 24 hours

	err = query.Count(&count).Error
	return count, err
}

func (_i *articleApprovalFlowsRepository) GetApprovedCountByPeriod(clientId *uuid.UUID, userLevelId uint, startDate, endDate time.Time) (count int64, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalStepLogs{})

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

	query = query.Where("user_level_id = ? AND action = 'approve' AND processed_at BETWEEN ? AND ?", userLevelId, startDate, endDate)

	err = query.Count(&count).Error
	return count, err
}

func (_i *articleApprovalFlowsRepository) GetRejectedCountByPeriod(clientId *uuid.UUID, userLevelId uint, startDate, endDate time.Time) (count int64, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalStepLogs{})

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

	query = query.Where("user_level_id = ? AND action = 'reject' AND processed_at BETWEEN ? AND ?", userLevelId, startDate, endDate)

	err = query.Count(&count).Error
	return count, err
}

func (_i *articleApprovalFlowsRepository) GetRevisionRequestCountByPeriod(clientId *uuid.UUID, userLevelId uint, startDate, endDate time.Time) (count int64, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalStepLogs{})

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

	query = query.Where("user_level_id = ? AND action = 'request_revision' AND processed_at BETWEEN ? AND ?", userLevelId, startDate, endDate)

	err = query.Count(&count).Error
	return count, err
}

// Workload Methods (simplified implementations)
func (_i *articleApprovalFlowsRepository) GetLevelWorkload(clientId *uuid.UUID, userLevelId uint) (workload map[string]interface{}, err error) {
	workload = make(map[string]interface{})

	// Get pending count
	pendingCount, err := _i.GetPendingCountByLevel(clientId, userLevelId)
	if err != nil {
		return nil, err
	}

	workload["pending_count"] = pendingCount
	workload["level_id"] = userLevelId

	return workload, nil
}

func (_i *articleApprovalFlowsRepository) GetTeamWorkloadComparison(clientId *uuid.UUID, userLevelId uint) (comparison []map[string]interface{}, err error) {
	// This would require more complex queries to get team members at the same level
	// For now, return empty slice
	comparison = make([]map[string]interface{}, 0)
	return comparison, nil
}

func (_i *articleApprovalFlowsRepository) GetWorkflowBottlenecks(clientId *uuid.UUID) (bottlenecks []map[string]interface{}, err error) {
	// This would require complex analysis of workflow steps
	// For now, return empty slice
	bottlenecks = make([]map[string]interface{}, 0)
	return bottlenecks, nil
}

// FindByArticleId finds an approval flow by article ID for a specific client
func (_i *articleApprovalFlowsRepository) FindByArticleId(clientId *uuid.UUID, articleId uint) (flow *entity.ArticleApprovalFlows, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalFlows{})

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

	query = query.Where("article_id = ?", articleId)
	query = query.Where("status_id IN (1, 2, 3, 4)") // active flows (pending, approved, rejected, revision_requested)
	query = query.Order("created_at DESC")

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

// GetPendingApprovalsByUserLevel gets pending approvals for a specific user level with pagination
func (_i *articleApprovalFlowsRepository) GetPendingApprovalsByUserLevel(clientId *uuid.UUID, userLevelId uint, page, limit int) (flows []*entity.ArticleApprovalFlows, paging paginator.Pagination, err error) {
	var count int64

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

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

	// Join with workflow steps to get approvals for this user level
	query = query.Joins("JOIN approval_workflows ON article_approval_flows.workflow_id = approval_workflows.id")
	query = query.Joins("JOIN approval_workflow_steps ON approval_workflows.id = approval_workflow_steps.workflow_id AND article_approval_flows.current_step = approval_workflow_steps.step_order")
	query = query.Where("approval_workflow_steps.required_user_level_id = ?", userLevelId)
	query = query.Where("article_approval_flows.status_id IN (1, 4)") // pending or revision_requested
	query = query.Where("article_approval_flows.current_step > 0")    // exclude completed flows (current_step = 0)

	// Preload related data
	query = query.Preload("Article").Preload("Workflow")

	// Count total
	err = query.Count(&count).Error
	if err != nil {
		return nil, paginator.Pagination{}, err
	}

	// Apply pagination
	offset := (page - 1) * limit
	query = query.Offset(offset).Limit(limit)
	query = query.Order("article_approval_flows.created_at ASC") // oldest first

	err = query.Find(&flows).Error
	if err != nil {
		return nil, paginator.Pagination{}, err
	}

	// Create pagination response
	paging = paginator.Pagination{
		Page:   page,
		Limit:  limit,
		Count:  count,
		Offset: offset,
	}

	return flows, paging, nil
}
