package repository

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

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

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

// ArticleApprovalStepLogsRepository define interface of IArticleApprovalStepLogsRepository
type ArticleApprovalStepLogsRepository interface {
	// Basic CRUD
	GetAll(clientId *uuid.UUID, req request.ArticleApprovalStepLogsQueryRequest) (logs []*entity.ArticleApprovalStepLogs, paging paginator.Pagination, err error)
	FindOne(clientId *uuid.UUID, id uint) (log *entity.ArticleApprovalStepLogs, err error)
	GetByApprovalFlowId(clientId *uuid.UUID, approvalFlowId uint) (logs []*entity.ArticleApprovalStepLogs, err error)
	Create(clientId *uuid.UUID, log *entity.ArticleApprovalStepLogs) (logReturn *entity.ArticleApprovalStepLogs, err error)
	Update(id uint, log *entity.ArticleApprovalStepLogs) (err error)
	Delete(clientId *uuid.UUID, id uint) (err error)

	// Approval History Methods
	GetApprovalHistory(clientId *uuid.UUID, articleId uint, page, limit int) (logs []*entity.ArticleApprovalStepLogs, paging paginator.Pagination, err error)
	GetUserApprovalHistory(clientId *uuid.UUID, userId uint, page, limit int, filters map[string]interface{}) (logs []*entity.ArticleApprovalStepLogs, paging paginator.Pagination, err error)
	GetLevelApprovalHistory(clientId *uuid.UUID, userLevelId uint, page, limit int, filters map[string]interface{}) (logs []*entity.ArticleApprovalStepLogs, paging paginator.Pagination, err error)

	// Analytics Methods
	GetApprovalTimeAnalytics(clientId *uuid.UUID, userLevelId uint, startDate, endDate time.Time) (analytics map[string]interface{}, err error)
	GetUserPerformanceMetrics(clientId *uuid.UUID, userId uint, startDate, endDate time.Time) (metrics map[string]interface{}, err error)
	GetWorkflowStepAnalytics(clientId *uuid.UUID, workflowId uint, stepOrder int) (analytics map[string]interface{}, err error)

	// Audit Methods
	GetAuditTrail(clientId *uuid.UUID, articleId uint) (trail []*entity.ArticleApprovalStepLogs, err error)
	GetRecentActions(clientId *uuid.UUID, userId uint, limit int) (logs []*entity.ArticleApprovalStepLogs, err error)
}

func NewArticleApprovalStepLogsRepository(db *database.Database, log zerolog.Logger) ArticleApprovalStepLogsRepository {
	return &articleApprovalStepLogsRepository{
		DB:  db,
		Log: log,
	}
}

// Basic CRUD implementations
func (_i *articleApprovalStepLogsRepository) GetAll(clientId *uuid.UUID, req request.ArticleApprovalStepLogsQueryRequest) (logs []*entity.ArticleApprovalStepLogs, paging paginator.Pagination, err error) {
	var count int64
	query := _i.DB.DB.Model(&entity.ArticleApprovalStepLogs{})

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

	// Apply filters based on request
	if req.ArticleApprovalFlowID != nil {
		query = query.Where("article_approval_flow_id = ?", *req.ArticleApprovalFlowID)
	}
	if req.WorkflowStepID != nil {
		query = query.Where("workflow_step_id = ?", *req.WorkflowStepID)
	}
	if req.ApproverUserID != nil {
		query = query.Where("approver_user_id = ?", *req.ApproverUserID)
	}
	if req.ApprovalStatusID != nil {
		query = query.Where("approval_status_id = ?", *req.ApprovalStatusID)
	}
	if req.DateFrom != nil {
		query = query.Where("approved_at >= ?", *req.DateFrom)
	}
	if req.DateTo != nil {
		query = query.Where("approved_at <= ?", *req.DateTo)
	}
	if req.IsAutoApproved != nil {
		query = query.Where("is_auto_approved = ?", *req.IsAutoApproved)
	}

	// Count total records
	query.Count(&count)

	// Apply sorting
	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 := "article_approval_step_logs.approved_at"
		query.Order(fmt.Sprintf("%s %s", sortBy, direction))
	}

	// Apply pagination (manual calculation for better performance)
	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).Preload("ApprovalFlow").Preload("Step").Preload("ActionBy").Preload("Status").Find(&logs).Error
	if err != nil {
		return
	}

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

	return logs, paging, nil
}

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

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

	query = query.Preload("ApprovalFlow").Preload("ApprovedBy").Preload("UserLevel")

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

func (_i *articleApprovalStepLogsRepository) GetByApprovalFlowId(clientId *uuid.UUID, approvalFlowId uint) (logs []*entity.ArticleApprovalStepLogs, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalStepLogs{})

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

	query = query.Where("approval_flow_id = ?", approvalFlowId)
	query = query.Preload("ApprovalFlow").Preload("ApprovedBy").Preload("UserLevel")
	query = query.Order("step_order ASC, processed_at ASC")

	err = query.Find(&logs).Error
	return logs, err
}

func (_i *articleApprovalStepLogsRepository) Create(clientId *uuid.UUID, log *entity.ArticleApprovalStepLogs) (logReturn *entity.ArticleApprovalStepLogs, err error) {
	log.ClientId = clientId
	log.ProcessedAt = time.Now()
	err = _i.DB.DB.Create(&log).Error
	return log, err
}

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

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

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

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

// Approval History Methods
func (_i *articleApprovalStepLogsRepository) GetApprovalHistory(clientId *uuid.UUID, articleId uint, page, limit int) (logs []*entity.ArticleApprovalStepLogs, paging paginator.Pagination, err error) {
	var count int64

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

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

	// Join with approval flows to filter by article
	query = query.Joins("JOIN article_approval_flows ON article_approval_step_logs.approval_flow_id = article_approval_flows.id")
	query = query.Where("article_approval_flows.article_id = ?", articleId)
	query = query.Preload("ApprovalFlow").Preload("ApprovedBy").Preload("UserLevel")
	query = query.Order("article_approval_step_logs.processed_at DESC")

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

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

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

	return logs, paging, nil
}

func (_i *articleApprovalStepLogsRepository) GetUserApprovalHistory(clientId *uuid.UUID, userId uint, page, limit int, filters map[string]interface{}) (logs []*entity.ArticleApprovalStepLogs, paging paginator.Pagination, err error) {
	var count int64

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

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

	query = query.Where("approved_by_id = ?", userId)

	// Apply filters
	if action, ok := filters["action"]; ok {
		query = query.Where("action = ?", action)
	}

	if startDate, ok := filters["start_date"]; ok {
		query = query.Where("processed_at >= ?", startDate)
	}

	if endDate, ok := filters["end_date"]; ok {
		query = query.Where("processed_at <= ?", endDate)
	}

	query = query.Preload("ApprovalFlow").Preload("ApprovedBy").Preload("UserLevel")
	query = query.Order("processed_at DESC")

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

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

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

	return logs, paging, nil
}

func (_i *articleApprovalStepLogsRepository) GetLevelApprovalHistory(clientId *uuid.UUID, userLevelId uint, page, limit int, filters map[string]interface{}) (logs []*entity.ArticleApprovalStepLogs, paging paginator.Pagination, err error) {
	var count int64

	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 = ?", userLevelId)

	// Apply filters
	if action, ok := filters["action"]; ok {
		query = query.Where("action = ?", action)
	}

	if startDate, ok := filters["start_date"]; ok {
		query = query.Where("processed_at >= ?", startDate)
	}

	if endDate, ok := filters["end_date"]; ok {
		query = query.Where("processed_at <= ?", endDate)
	}

	query = query.Preload("ApprovalFlow").Preload("ApprovedBy").Preload("UserLevel")
	query = query.Order("processed_at DESC")

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

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

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

	return logs, paging, nil
}

// Analytics Methods
func (_i *articleApprovalStepLogsRepository) GetApprovalTimeAnalytics(clientId *uuid.UUID, userLevelId uint, startDate, endDate time.Time) (analytics map[string]interface{}, err error) {
	analytics = make(map[string]interface{})

	// Get average approval time for this level
	var avgTime float64
	query := _i.DB.DB.Model(&entity.ArticleApprovalStepLogs{})

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

	query = query.Where("user_level_id = ? AND action IN ('approve', 'reject') AND processed_at BETWEEN ? AND ?", userLevelId, startDate, endDate)
	query = query.Select("AVG(EXTRACT(EPOCH FROM (processed_at - created_at))) as avg_time")

	err = query.Scan(&avgTime).Error
	if err != nil {
		return nil, err
	}

	analytics["average_approval_time_seconds"] = avgTime
	analytics["level_id"] = userLevelId
	analytics["period_start"] = startDate
	analytics["period_end"] = endDate

	return analytics, nil
}

func (_i *articleApprovalStepLogsRepository) GetUserPerformanceMetrics(clientId *uuid.UUID, userId uint, startDate, endDate time.Time) (metrics map[string]interface{}, err error) {
	metrics = make(map[string]interface{})

	// Get counts by action
	var approvedCount, rejectedCount, revisionCount int64

	query := _i.DB.DB.Model(&entity.ArticleApprovalStepLogs{})
	if clientId != nil {
		query = query.Where("client_id = ?", clientId)
	}
	query = query.Where("approved_by_id = ? AND processed_at BETWEEN ? AND ?", userId, startDate, endDate)

	// Approved count
	query.Where("action = 'approve'").Count(&approvedCount)

	// Rejected count
	query.Where("action = 'reject'").Count(&rejectedCount)

	// Revision requested count
	query.Where("action = 'request_revision'").Count(&revisionCount)

	metrics["approved_count"] = approvedCount
	metrics["rejected_count"] = rejectedCount
	metrics["revision_requested_count"] = revisionCount
	metrics["total_processed"] = approvedCount + rejectedCount + revisionCount
	metrics["user_id"] = userId
	metrics["period_start"] = startDate
	metrics["period_end"] = endDate

	return metrics, nil
}

func (_i *articleApprovalStepLogsRepository) GetWorkflowStepAnalytics(clientId *uuid.UUID, workflowId uint, stepOrder int) (analytics map[string]interface{}, err error) {
	analytics = make(map[string]interface{})

	// Get step performance metrics
	var totalProcessed, approvedCount, rejectedCount int64

	query := _i.DB.DB.Model(&entity.ArticleApprovalStepLogs{})
	if clientId != nil {
		query = query.Where("client_id = ?", clientId)
	}

	// Join with approval flows to filter by workflow
	query = query.Joins("JOIN article_approval_flows ON article_approval_step_logs.approval_flow_id = article_approval_flows.id")
	query = query.Where("article_approval_flows.workflow_id = ? AND article_approval_step_logs.step_order = ?", workflowId, stepOrder)

	// Total processed
	query.Count(&totalProcessed)

	// Approved count
	query.Where("article_approval_step_logs.action = 'approve'").Count(&approvedCount)

	// Rejected count
	query.Where("article_approval_step_logs.action = 'reject'").Count(&rejectedCount)

	analytics["workflow_id"] = workflowId
	analytics["step_order"] = stepOrder
	analytics["total_processed"] = totalProcessed
	analytics["approved_count"] = approvedCount
	analytics["rejected_count"] = rejectedCount
	analytics["approval_rate"] = float64(approvedCount) / float64(totalProcessed) * 100

	return analytics, nil
}

// Audit Methods
func (_i *articleApprovalStepLogsRepository) GetAuditTrail(clientId *uuid.UUID, articleId uint) (trail []*entity.ArticleApprovalStepLogs, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalStepLogs{})

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

	// Join with approval flows to filter by article
	query = query.Joins("JOIN article_approval_flows ON article_approval_step_logs.approval_flow_id = article_approval_flows.id")
	query = query.Where("article_approval_flows.article_id = ?", articleId)
	query = query.Preload("ApprovalFlow").Preload("ApprovedBy").Preload("UserLevel")
	query = query.Order("article_approval_step_logs.processed_at ASC")

	err = query.Find(&trail).Error
	return trail, err
}

func (_i *articleApprovalStepLogsRepository) GetRecentActions(clientId *uuid.UUID, userId uint, limit int) (logs []*entity.ArticleApprovalStepLogs, err error) {
	query := _i.DB.DB.Model(&entity.ArticleApprovalStepLogs{})

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

	query = query.Where("approved_by_id = ?", userId)
	query = query.Preload("ApprovalFlow").Preload("ApprovedBy").Preload("UserLevel")
	query = query.Order("processed_at DESC")
	query = query.Limit(limit)

	err = query.Find(&logs).Error
	return logs, err
}
