package services

import (
	"errors"
	"time"

	"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/models"
	"gorm.io/gorm"
)

// SpeakingService 口语练习服务
type SpeakingService struct {
	db *gorm.DB
}

// NewSpeakingService 创建口语练习服务实例
func NewSpeakingService(db *gorm.DB) *SpeakingService {
	return &SpeakingService{
		db: db,
	}
}

// ==================== 口语场景管理 ====================

// GetSpeakingScenarios 获取口语场景列表
func (s *SpeakingService) GetSpeakingScenarios(level, category string, page, pageSize int) ([]models.SpeakingScenario, int64, error) {
	var scenarios []models.SpeakingScenario
	var total int64

	query := s.db.Model(&models.SpeakingScenario{}).Where("is_active = ?", true)

	// 添加过滤条件
	if level != "" {
		query = query.Where("level = ?", level)
	}
	if category != "" {
		query = query.Where("category = ?", category)
	}

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&scenarios).Error; err != nil {
		return nil, 0, err
	}

	return scenarios, total, nil
}

// GetSpeakingScenario 根据ID获取口语场景
func (s *SpeakingService) GetSpeakingScenario(id string) (*models.SpeakingScenario, error) {
	var scenario models.SpeakingScenario
	if err := s.db.Where("id = ? AND is_active = ?", id, true).First(&scenario).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("口语场景不存在")
		}
		return nil, err
	}
	return &scenario, nil
}

// CreateSpeakingScenario 创建口语场景
func (s *SpeakingService) CreateSpeakingScenario(scenario *models.SpeakingScenario) error {
	scenario.CreatedAt = time.Now()
	scenario.UpdatedAt = time.Now()
	return s.db.Create(scenario).Error
}

// UpdateSpeakingScenario 更新口语场景
func (s *SpeakingService) UpdateSpeakingScenario(id string, updateData *models.SpeakingScenario) error {
	updateData.UpdatedAt = time.Now()
	result := s.db.Model(&models.SpeakingScenario{}).Where("id = ? AND is_active = ?", id, true).Updates(updateData)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return errors.New("口语场景不存在")
	}
	return nil
}

// DeleteSpeakingScenario 删除口语场景（软删除）
func (s *SpeakingService) DeleteSpeakingScenario(id string) error {
	result := s.db.Model(&models.SpeakingScenario{}).Where("id = ?", id).Update("is_active", false)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return errors.New("口语场景不存在")
	}
	return nil
}

// SearchSpeakingScenarios 搜索口语场景
func (s *SpeakingService) SearchSpeakingScenarios(keyword string, level, category string, page, pageSize int) ([]models.SpeakingScenario, int64, error) {
	var scenarios []models.SpeakingScenario
	var total int64

	query := s.db.Model(&models.SpeakingScenario{}).Where("is_active = ?", true)

	// 关键词搜索
	if keyword != "" {
		query = query.Where("title LIKE ? OR description LIKE ?", "%"+keyword+"%", "%"+keyword+"%")
	}

	// 添加过滤条件
	if level != "" {
		query = query.Where("level = ?", level)
	}
	if category != "" {
		query = query.Where("category = ?", category)
	}

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&scenarios).Error; err != nil {
		return nil, 0, err
	}

	return scenarios, total, nil
}

// GetRecommendedScenarios 获取推荐的口语场景
func (s *SpeakingService) GetRecommendedScenarios(userID string, limit int) ([]models.SpeakingScenario, error) {
    var scenarios []models.SpeakingScenario

    // 简单的推荐逻辑：基于用户水平和最近练习情况
    // 这里可以根据实际需求实现更复杂的推荐算法
    query := `
        SELECT 
            s.*,
            CASE WHEN ar.cnt IS NULL OR ar.cnt = 0 THEN 0 ELSE 1 END AS has_record
        FROM ai_speaking_scenarios s
        LEFT JOIN (
            SELECT scenario_id, COUNT(*) AS cnt
            FROM ai_speaking_records
            WHERE user_id = ?
            GROUP BY scenario_id
        ) ar ON ar.scenario_id = s.id
        WHERE s.is_active = true
        ORDER BY has_record ASC, s.created_at DESC
        LIMIT ?
    `

    if err := s.db.Raw(query, userID, limit).Scan(&scenarios).Error; err != nil {
        return nil, err
    }

    return scenarios, nil
}

// ==================== 口语练习记录管理 ====================

// CreateSpeakingRecord 创建口语练习记录
func (s *SpeakingService) CreateSpeakingRecord(record *models.SpeakingRecord) error {
	record.CreatedAt = time.Now()
	record.UpdatedAt = time.Now()
	return s.db.Create(record).Error
}

// UpdateSpeakingRecord 更新口语练习记录
func (s *SpeakingService) UpdateSpeakingRecord(id string, updateData *models.SpeakingRecord) error {
	updateData.UpdatedAt = time.Now()
	result := s.db.Model(&models.SpeakingRecord{}).Where("id = ?", id).Updates(updateData)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return errors.New("口语练习记录不存在")
	}
	return nil
}

// GetSpeakingRecord 根据ID获取口语练习记录
func (s *SpeakingService) GetSpeakingRecord(id string) (*models.SpeakingRecord, error) {
	var record models.SpeakingRecord
	if err := s.db.Preload("SpeakingScenario").Where("id = ?", id).First(&record).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("口语练习记录不存在")
		}
		return nil, err
	}
	return &record, nil
}

// GetUserSpeakingRecords 获取用户的口语练习记录
func (s *SpeakingService) GetUserSpeakingRecords(userID string, page, pageSize int) ([]models.SpeakingRecord, int64, error) {
	var records []models.SpeakingRecord
	var total int64

	query := s.db.Model(&models.SpeakingRecord{}).Where("user_id = ?", userID)

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (page - 1) * pageSize
	if err := query.Preload("SpeakingScenario").Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&records).Error; err != nil {
		return nil, 0, err
	}

	return records, total, nil
}

// SubmitSpeaking 提交口语练习
func (s *SpeakingService) SubmitSpeaking(recordID string, audioURL, transcript string) error {
    updateData := map[string]interface{}{
        "audio_url":   audioURL,
        "transcript":  transcript,
        "completed_at": time.Now(),
        "updated_at":  time.Now(),
    }

	result := s.db.Model(&models.SpeakingRecord{}).Where("id = ?", recordID).Updates(updateData)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return errors.New("口语练习记录不存在")
	}
	return nil
}

// GradeSpeaking 评分口语练习
func (s *SpeakingService) GradeSpeaking(recordID string, pronunciationScore, fluencyScore, accuracyScore, overallScore float64, feedback, suggestions string) error {
	updateData := map[string]interface{}{
		"pronunciation_score": pronunciationScore,
		"fluency_score":       fluencyScore,
		"accuracy_score":      accuracyScore,
		"overall_score":       overallScore,
		"feedback":            feedback,
		"suggestions":         suggestions,
		"graded_at":           time.Now(),
		"updated_at":          time.Now(),
	}

	result := s.db.Model(&models.SpeakingRecord{}).Where("id = ?", recordID).Updates(updateData)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return errors.New("口语练习记录不存在")
	}
	return nil
}

// ==================== 口语学习统计 ====================

// GetUserSpeakingStats 获取用户口语学习统计
func (s *SpeakingService) GetUserSpeakingStats(userID string) (map[string]interface{}, error) {
	stats := make(map[string]interface{})

	// 总练习次数
	var totalRecords int64
	if err := s.db.Model(&models.SpeakingRecord{}).Where("user_id = ?", userID).Count(&totalRecords).Error; err != nil {
		return nil, err
	}
	stats["total_records"] = totalRecords

    // 已完成练习次数
    var completedRecords int64
    if err := s.db.Model(&models.SpeakingRecord{}).Where("user_id = ? AND completed_at IS NOT NULL", userID).Count(&completedRecords).Error; err != nil {
        return nil, err
    }
    stats["completed_records"] = completedRecords

	// 已评分练习次数
	var gradedRecords int64
	if err := s.db.Model(&models.SpeakingRecord{}).Where("user_id = ? AND overall_score IS NOT NULL", userID).Count(&gradedRecords).Error; err != nil {
		return nil, err
	}
	stats["graded_records"] = gradedRecords

	// 平均分数
	var avgScores struct {
		Pronunciation float64 `json:"pronunciation"`
		Fluency       float64 `json:"fluency"`
		Accuracy      float64 `json:"accuracy"`
		Overall       float64 `json:"overall"`
	}
	if err := s.db.Model(&models.SpeakingRecord{}).Where("user_id = ? AND overall_score IS NOT NULL", userID).Select(
		"AVG(pronunciation_score) as pronunciation, AVG(fluency_score) as fluency, AVG(accuracy_score) as accuracy, AVG(overall_score) as overall",
	).Scan(&avgScores).Error; err != nil {
		return nil, err
	}
	stats["average_scores"] = avgScores

	// 总练习时长
    var totalDuration int64
    if err := s.db.Model(&models.SpeakingRecord{}).Where("user_id = ? AND duration IS NOT NULL", userID).Select("COALESCE(SUM(duration), 0)").Scan(&totalDuration).Error; err != nil {
        return nil, err
    }
    stats["total_duration"] = totalDuration

	// 平均练习时长
	var avgDuration float64
	if completedRecords > 0 {
		avgDuration = float64(totalDuration) / float64(completedRecords)
	}
	stats["average_duration"] = avgDuration

	// 连续练习天数
	continuousDays, err := s.calculateContinuousSpeakingDays(userID)
	if err != nil {
		return nil, err
	}
	stats["continuous_days"] = continuousDays

	// 按难度级别统计
	levelStats, err := s.getSpeakingStatsByLevel(userID)
	if err != nil {
		return nil, err
	}
	stats["stats_by_level"] = levelStats

	return stats, nil
}

// calculateContinuousSpeakingDays 计算连续练习天数
func (s *SpeakingService) calculateContinuousSpeakingDays(userID string) (int, error) {
	var dates []time.Time
    if err := s.db.Model(&models.SpeakingRecord{}).Where("user_id = ? AND completed_at IS NOT NULL", userID).Select("DATE(created_at) as date").Group("DATE(created_at)").Order("date DESC").Pluck("date", &dates).Error; err != nil {
        return 0, err
    }

	if len(dates) == 0 {
		return 0, nil
	}

	continuousDays := 1
	for i := 1; i < len(dates); i++ {
		diff := dates[i-1].Sub(dates[i]).Hours() / 24
		if diff == 1 {
			continuousDays++
		} else {
			break
		}
	}

	return continuousDays, nil
}

// getSpeakingStatsByLevel 获取按难度级别的统计
func (s *SpeakingService) getSpeakingStatsByLevel(userID string) (map[string]interface{}, error) {
	var results []struct {
		Level string  `json:"level"`
		Count int64   `json:"count"`
		Score float64 `json:"avg_score"`
	}

    query := `
        SELECT 
            ss.level,
            COUNT(sr.id) as count,
            AVG(sr.overall_score) as avg_score
        FROM ai_speaking_records sr
        JOIN ai_speaking_scenarios ss ON sr.scenario_id = ss.id
        WHERE sr.user_id = ? AND sr.overall_score IS NOT NULL
        GROUP BY ss.level
    `

	if err := s.db.Raw(query, userID).Scan(&results).Error; err != nil {
		return nil, err
	}

	stats := make(map[string]interface{})
	for _, result := range results {
		stats[result.Level] = map[string]interface{}{
			"count":     result.Count,
			"avg_score": result.Score,
		}
	}

	return stats, nil
}

// GetSpeakingProgress 获取口语学习进度
func (s *SpeakingService) GetSpeakingProgress(userID, scenarioID string) (map[string]interface{}, error) {
	progress := make(map[string]interface{})

	// 该场景的练习记录
	var records []models.SpeakingRecord
	if err := s.db.Where("user_id = ? AND scenario_id = ?", userID, scenarioID).Order("created_at ASC").Find(&records).Error; err != nil {
		return nil, err
	}

	progress["total_attempts"] = len(records)

	if len(records) == 0 {
		progress["completed"] = false
		progress["best_score"] = 0
		progress["latest_score"] = 0
		progress["improvement"] = 0
		return progress, nil
	}

	// 最佳分数
	var bestScore float64
	for _, record := range records {
		if record.OverallScore != nil && *record.OverallScore > bestScore {
			bestScore = *record.OverallScore
		}
	}
	progress["best_score"] = bestScore

	// 最新分数
	latestRecord := records[len(records)-1]
	latestScore := 0.0
	if latestRecord.OverallScore != nil {
		latestScore = *latestRecord.OverallScore
	}
	progress["latest_score"] = latestScore

	// 是否完成（有评分记录）
	progress["completed"] = latestRecord.OverallScore != nil

	// 进步情况（最新分数与第一次分数的差值）
	improvement := 0.0
	if len(records) > 1 && records[0].OverallScore != nil && latestRecord.OverallScore != nil {
		improvement = *latestRecord.OverallScore - *records[0].OverallScore
	}
	progress["improvement"] = improvement

	return progress, nil
}