package repositories

import (
	"log"
	"time"

	"github.com/niangaodev/art-code/config"
	"github.com/niangaodev/art-code/models"
	"gorm.io/gorm"
)

// ========== 视频分类 ==========

func GetVideoCategories() ([]models.VideoCategory, error) {
	var list []models.VideoCategory
	err := config.DB.Model(&models.VideoCategory{}).
		Where("deleted_at = ?", 0).
		Order("sort_order ASC, id ASC").
		Find(&list).Error
	return list, err
}

func GetVideoCategoryByID(id uint) (*models.VideoCategory, error) {
	var item models.VideoCategory
	err := config.DB.Model(&models.VideoCategory{}).
		Where("id = ? AND deleted_at = ?", id, 0).
		First(&item).Error
	if err == gorm.ErrRecordNotFound {
		return nil, nil
	}
	return &item, err
}

func CreateVideoCategory(item *models.VideoCategory) error {
	return config.DB.Create(item).Error
}

func UpdateVideoCategory(item *models.VideoCategory) error {
	return config.DB.Model(&models.VideoCategory{}).
		Where("id = ? AND deleted_at = ?", item.ID, 0).
		Updates(map[string]interface{}{
			"name":        item.Name,
			"slug":        item.Slug,
			"description": item.Description,
			"sort_order":  item.SortOrder,
			"updated_at":  time.Now().Unix(),
		}).Error
}

func DeleteVideoCategory(id uint) error {
	return config.DB.Model(&models.VideoCategory{}).
		Where("id = ?", id).
		Update("deleted_at", time.Now().Unix()).Error
}

func BuildVideoCategoryResponse(item *models.VideoCategory) models.VideoCategoryResponse {
	var videoCount, albumCount int64
	config.DB.Model(&models.Video{}).
		Where("category_id = ? AND deleted_at = ? AND is_published = ?", item.ID, 0, 1).
		Count(&videoCount)
	config.DB.Model(&models.VideoAlbum{}).
		Where("category_id = ? AND deleted_at = ? AND is_active = ?", item.ID, 0, 1).
		Count(&albumCount)
	return models.VideoCategoryResponse{
		ID:          item.ID,
		Name:        item.Name,
		Slug:        item.Slug,
		Description: item.Description,
		SortOrder:   item.SortOrder,
		CreatedAt:   formatTimestamp(item.CreatedAt),
		UpdatedAt:   formatTimestamp(item.UpdatedAt),
		VideoCount:  videoCount,
		AlbumCount:  albumCount,
	}
}

func BuildVideoCategoriesResponse(list []models.VideoCategory) []models.VideoCategoryResponse {
	res := make([]models.VideoCategoryResponse, 0, len(list))
	for i := range list {
		res = append(res, BuildVideoCategoryResponse(&list[i]))
	}
	return res
}

// ========== 视频专辑 ==========

func GetVideoAlbums(categoryID uint) ([]models.VideoAlbum, error) {
	var list []models.VideoAlbum
	q := config.DB.Model(&models.VideoAlbum{}).Where("deleted_at = ?", 0)
	if categoryID > 0 {
		q = q.Where("category_id = ?", categoryID)
	}
	err := q.Order("sort_order ASC, created_at DESC").Find(&list).Error
	return list, err
}

func GetActiveVideoAlbums(categoryID uint) ([]models.VideoAlbum, error) {
	var list []models.VideoAlbum
	q := config.DB.Model(&models.VideoAlbum{}).Where("deleted_at = ? AND is_active = ?", 0, 1)
	if categoryID > 0 {
		q = q.Where("category_id = ?", categoryID)
	}
	err := q.Order("sort_order ASC, created_at DESC").Find(&list).Error
	return list, err
}

func GetVideoAlbumByID(id uint) (*models.VideoAlbum, error) {
	var item models.VideoAlbum
	err := config.DB.Model(&models.VideoAlbum{}).
		Where("id = ? AND deleted_at = ?", id, 0).
		First(&item).Error
	if err == gorm.ErrRecordNotFound {
		return nil, nil
	}
	return &item, err
}

func CreateVideoAlbum(item *models.VideoAlbum) error {
	return config.DB.Create(item).Error
}

func UpdateVideoAlbum(item *models.VideoAlbum) error {
	return config.DB.Model(&models.VideoAlbum{}).
		Where("id = ? AND deleted_at = ?", item.ID, 0).
		Updates(map[string]interface{}{
			"name":        item.Name,
			"description": item.Description,
			"cover":       item.Cover,
			"category_id": item.CategoryID,
			"is_active":   item.IsActive,
			"sort_order":  item.SortOrder,
			"updated_at":  time.Now().Unix(),
		}).Error
}

func DeleteVideoAlbum(id uint) error {
	return config.DB.Model(&models.VideoAlbum{}).
		Where("id = ?", id).
		Update("deleted_at", time.Now().Unix()).Error
}

// GetAlbumVideoCount 统计专辑内视频数量；publishedOnly 为 true 时仅统计已发布视频
func GetAlbumVideoCount(albumID uint, publishedOnly bool) int64 {
	var count int64
	q := config.DB.Model(&models.AlbumVideo{}).
		Joins("JOIN videos v ON v.id = album_videos.video_id").
		Where("album_videos.album_id = ? AND v.deleted_at = ?", albumID, 0)
	if publishedOnly {
		q = q.Where("v.is_published = ?", 1)
	}
	q.Count(&count)
	return count
}

// GetAlbumLatestVideoUpdatedAt 获取专辑内视频最新更新时间戳
func GetAlbumLatestVideoUpdatedAt(albumID uint, publishedOnly bool) int64 {
	var ts int64
	q := config.DB.Model(&models.Video{}).
		Select("COALESCE(MAX(videos.updated_at), 0)").
		Joins("JOIN album_videos av ON av.video_id = videos.id").
		Where("av.album_id = ? AND videos.deleted_at = ?", albumID, 0)
	if publishedOnly {
		q = q.Where("videos.is_published = ?", 1)
	}
	q.Scan(&ts)
	return ts
}

// GetAlbumPreviewVideos 获取专辑预览视频列表（按 sort_order，最多 limit 条）
func GetAlbumPreviewVideos(albumID uint, limit int, publishedOnly bool) ([]models.Video, error) {
	if limit <= 0 {
		limit = 5
	}
	var list []models.Video
	q := config.DB.Model(&models.Video{}).
		Joins("JOIN album_videos av ON av.video_id = videos.id").
		Where("av.album_id = ? AND videos.deleted_at = ?", albumID, 0)
	if publishedOnly {
		q = q.Where("videos.is_published = ?", 1)
	}
	err := q.Order("av.sort_order ASC, av.created_at ASC").Limit(limit).Find(&list).Error
	return list, err
}

// BuildVideoAlbumResponse 构建专辑响应；publishedOnly 控制统计与预览是否仅含已发布视频
func BuildVideoAlbumResponse(item *models.VideoAlbum, publishedOnly bool) models.VideoAlbumResponse {
	categoryName := ""
	if cat, _ := GetVideoCategoryByID(item.CategoryID); cat != nil {
		categoryName = cat.Name
	}
	latestTs := GetAlbumLatestVideoUpdatedAt(item.ID, publishedOnly)
	resp := models.VideoAlbumResponse{
		ID:           item.ID,
		Name:         item.Name,
		Description:  item.Description,
		Cover:        item.Cover,
		CategoryID:   item.CategoryID,
		CategoryName: categoryName,
		IsActive:     item.IsActive,
		SortOrder:    item.SortOrder,
		CreatedAt:    formatTimestamp(item.CreatedAt),
		UpdatedAt:    formatTimestamp(item.UpdatedAt),
		VideoCount:   GetAlbumVideoCount(item.ID, publishedOnly),
	}
	if latestTs > 0 {
		resp.LatestVideoUpdatedAt = formatTimestamp(latestTs)
	}
	if previews, err := GetAlbumPreviewVideos(item.ID, 5, publishedOnly); err == nil && len(previews) > 0 {
		resp.PreviewVideos = BuildVideosResponse(previews)
	}
	return resp
}

func BuildVideoAlbumsResponse(list []models.VideoAlbum, publishedOnly bool) []models.VideoAlbumResponse {
	res := make([]models.VideoAlbumResponse, 0, len(list))
	for i := range list {
		res = append(res, BuildVideoAlbumResponse(&list[i], publishedOnly))
	}
	return res
}

// ========== 视频 ==========

func GetVideos(categoryID uint, publishedOnly bool) ([]models.Video, error) {
	var list []models.Video
	q := config.DB.Model(&models.Video{}).Where("deleted_at = ?", 0)
	if categoryID > 0 {
		q = q.Where("category_id = ?", categoryID)
	}
	if publishedOnly {
		q = q.Where("is_published = ?", 1)
	}
	err := q.Order("created_at DESC").Find(&list).Error
	return list, err
}

func GetVideoByID(id string) (*models.Video, error) {
	var item models.Video
	err := config.DB.Model(&models.Video{}).
		Where("id = ? AND deleted_at = ?", id, 0).
		First(&item).Error
	if err == gorm.ErrRecordNotFound {
		return nil, nil
	}
	return &item, err
}

func CreateVideo(item *models.Video) error {
	return config.DB.Create(item).Error
}

func UpdateVideo(item *models.Video) error {
	return config.DB.Model(&models.Video{}).
		Where("id = ? AND deleted_at = ?", item.ID, 0).
		Updates(map[string]interface{}{
			"title":        item.Title,
			"description":  item.Description,
			"video_url":    item.VideoURL,
			"cover":        item.Cover,
			"poster":       item.Poster,
			"category_id":  item.CategoryID,
			"duration":     item.Duration,
			"is_published": item.IsPublished,
			"updated_at":   time.Now().Unix(),
		}).Error
}

func DeleteVideo(id string) error {
	return config.DB.Model(&models.Video{}).
		Where("id = ?", id).
		Update("deleted_at", time.Now().Unix()).Error
}

func BuildVideoResponse(item *models.Video) models.VideoResponse {
	categoryName := ""
	if cat, _ := GetVideoCategoryByID(item.CategoryID); cat != nil {
		categoryName = cat.Name
	}
	poster := item.Poster
	if poster == "" {
		poster = item.Cover
	}
	return models.VideoResponse{
		ID:           item.ID,
		Title:        item.Title,
		Description:  item.Description,
		VideoURL:     item.VideoURL,
		Cover:        item.Cover,
		Poster:       poster,
		CategoryID:   item.CategoryID,
		CategoryName: categoryName,
		Duration:     item.Duration,
		IsPublished:  item.IsPublished,
		CreatedAt:    formatTimestamp(item.CreatedAt),
		UpdatedAt:    formatTimestamp(item.UpdatedAt),
	}
}

func BuildVideosResponse(list []models.Video) []models.VideoResponse {
	res := make([]models.VideoResponse, 0, len(list))
	for i := range list {
		res = append(res, BuildVideoResponse(&list[i]))
	}
	return res
}

// ResolveVideoURL 根据 video_id 解析播放地址
func ResolveVideoURL(videoID string) string {
	if videoID == "" {
		return ""
	}
	v, err := GetVideoByID(videoID)
	if err != nil || v == nil {
		log.Printf("ResolveVideoURL: video not found %s", videoID)
		return ""
	}
	return v.VideoURL
}

// ========== 专辑视频关联 ==========

func GetVideosByAlbumID(albumID uint, publishedOnly bool) ([]models.Video, error) {
	var list []models.Video
	q := config.DB.Model(&models.Video{}).
		Joins("JOIN album_videos av ON av.video_id = videos.id").
		Where("av.album_id = ? AND videos.deleted_at = ?", albumID, 0)
	if publishedOnly {
		q = q.Where("videos.is_published = ?", 1)
	}
	err := q.Order("av.sort_order ASC, av.created_at ASC").Find(&list).Error
	return list, err
}

func AddVideoToAlbum(albumID uint, videoID string, sortOrder uint) error {
	av := models.AlbumVideo{
		AlbumID:   albumID,
		VideoID:   videoID,
		SortOrder: sortOrder,
		CreatedAt: time.Now().Unix(),
	}
	return config.DB.Create(&av).Error
}

func RemoveVideoFromAlbum(albumID uint, videoID string) error {
	return config.DB.Where("album_id = ? AND video_id = ?", albumID, videoID).
		Delete(&models.AlbumVideo{}).Error
}

func SyncAlbumVideos(albumID uint, videoIDs []string) error {
	if err := config.DB.Where("album_id = ?", albumID).Delete(&models.AlbumVideo{}).Error; err != nil {
		return err
	}
	for i, vid := range videoIDs {
		if vid == "" {
			continue
		}
		if err := AddVideoToAlbum(albumID, vid, uint(i+1)); err != nil {
			log.Printf("SyncAlbumVideos error: %v", err)
			return err
		}
	}
	return nil
}

// GetAlbumIDsByVideoID 查询视频所属专辑 ID 列表
func GetAlbumIDsByVideoID(videoID string) ([]uint, error) {
	var ids []uint
	err := config.DB.Model(&models.AlbumVideo{}).
		Where("video_id = ?", videoID).
		Pluck("album_id", &ids).Error
	return ids, err
}

// GetPrimaryActiveAlbumForVideo 取视频关联的第一个启用专辑（按专辑 sort_order）
func GetPrimaryActiveAlbumForVideo(videoID string) (*models.VideoAlbum, error) {
	var album models.VideoAlbum
	err := config.DB.Model(&models.VideoAlbum{}).
		Joins("JOIN album_videos av ON av.album_id = video_albums.id").
		Where("av.video_id = ? AND video_albums.deleted_at = ? AND video_albums.is_active = ?", videoID, 0, 1).
		Order("video_albums.sort_order ASC, video_albums.id ASC").
		First(&album).Error
	if err == gorm.ErrRecordNotFound {
		return nil, nil
	}
	return &album, err
}

// GetAlbumVideoNeighbors 获取专辑内当前视频的前后邻居（按 sort_order）
func GetAlbumVideoNeighbors(albumID uint, videoID string, before, after int, publishedOnly bool) (prev, next []models.Video, err error) {
	list, err := GetVideosByAlbumID(albumID, publishedOnly)
	if err != nil {
		return nil, nil, err
	}
	idx := -1
	for i, v := range list {
		if v.ID == videoID {
			idx = i
			break
		}
	}
	if idx < 0 {
		return nil, nil, nil
	}
	start := idx - before
	if start < 0 {
		start = 0
	}
	prev = list[start:idx]
	end := idx + after + 1
	if end > len(list) {
		end = len(list)
	}
	next = list[idx+1 : end]
	return prev, next, nil
}

// BuildVideoDetailResponse 构建视频详情响应（含专辑前后导航）
func BuildVideoDetailResponse(item *models.Video) models.VideoDetailResponse {
	resp := models.VideoDetailResponse{
		VideoResponse: BuildVideoResponse(item),
	}
	album, err := GetPrimaryActiveAlbumForVideo(item.ID)
	if err != nil || album == nil {
		return resp
	}
	prev, next, err := GetAlbumVideoNeighbors(album.ID, item.ID, 2, 2, true)
	if err != nil {
		return resp
	}
	resp.AlbumContext = &models.VideoAlbumNavContext{
		AlbumID:    album.ID,
		AlbumName:  album.Name,
		PrevVideos: BuildVideosResponse(prev),
		NextVideos: BuildVideosResponse(next),
	}
	return resp
}

// GetAlbumIDsByVideoIDList 供管理端读取视频所属专辑
func GetAlbumIDsByVideoIDList(videoID string) []uint {
	ids, err := GetAlbumIDsByVideoID(videoID)
	if err != nil {
		return []uint{}
	}
	return ids
}

// BuildAdminVideoResponse 构建管理端视频响应（含 albumIds）
func BuildAdminVideoResponse(item *models.Video) models.AdminVideoResponse {
	return models.AdminVideoResponse{
		VideoResponse: BuildVideoResponse(item),
		AlbumIDs:      GetAlbumIDsByVideoIDList(item.ID),
	}
}

// BuildAdminVideosResponse 批量构建管理端视频响应
func BuildAdminVideosResponse(list []models.Video) []models.AdminVideoResponse {
	res := make([]models.AdminVideoResponse, 0, len(list))
	for i := range list {
		res = append(res, BuildAdminVideoResponse(&list[i]))
	}
	return res
}

// SyncVideoAlbums 同步视频所属专辑（先删后建）
func SyncVideoAlbums(videoID string, albumIDs []uint) error {
	if err := config.DB.Where("video_id = ?", videoID).Delete(&models.AlbumVideo{}).Error; err != nil {
		return err
	}
	for i, albumID := range albumIDs {
		if albumID == 0 {
			continue
		}
		if err := AddVideoToAlbum(albumID, videoID, uint(i+1)); err != nil {
			log.Printf("SyncVideoAlbums error: %v", err)
			return err
		}
	}
	return nil
}
