package course_management

import (
	"Yimaru-Backend/internal/domain"
	"Yimaru-Backend/internal/pkgs/vimeo"
	vimeoservice "Yimaru-Backend/internal/services/vimeo"
	"context"
	"fmt"
	"io"
	"net/http"
	"path"
	"time"
)

func (s *Service) CreateSubCourseVideo(
	ctx context.Context,
	subCourseID int64,
	title string,
	description *string,
	videoURL string,
	duration int32,
	resolution *string,
	instructorID *string,
	thumbnail *string,
	visibility *string,
	displayOrder *int32,
	status *string,
) (domain.SubCourseVideo, error) {
	// Default to DIRECT provider when no Vimeo info provided
	provider := string(domain.VideoHostProviderDirect)
	return s.courseStore.CreateSubCourseVideo(
		ctx, subCourseID, title, description, videoURL, duration,
		resolution, instructorID, thumbnail, visibility, displayOrder, status,
		nil, nil, nil, nil, &provider,
	)
}

// CreateSubCourseVideoWithVimeo creates a video and uploads it to Vimeo
func (s *Service) CreateSubCourseVideoWithVimeo(
	ctx context.Context,
	subCourseID int64,
	title string,
	description *string,
	sourceURL string,
	fileSize int64,
	duration int32,
	resolution *string,
	instructorID *string,
	thumbnail *string,
	visibility *string,
	displayOrder *int32,
) (domain.SubCourseVideo, error) {
	if s.vimeoSvc == nil {
		return domain.SubCourseVideo{}, fmt.Errorf("vimeo service is not configured")
	}

	descStr := ""
	if description != nil {
		descStr = *description
	}

	var uploadResult *vimeoservice.UploadResult
	var err error

	if s.cloudConvertSvc != nil {
		httpClient := &http.Client{Timeout: 30 * time.Minute}
		req, reqErr := http.NewRequestWithContext(ctx, http.MethodGet, sourceURL, nil)
		if reqErr != nil {
			return domain.SubCourseVideo{}, fmt.Errorf("failed to create download request: %w", reqErr)
		}
		resp, dlErr := httpClient.Do(req)
		if dlErr != nil {
			return domain.SubCourseVideo{}, fmt.Errorf("failed to download source video: %w", dlErr)
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			return domain.SubCourseVideo{}, fmt.Errorf("failed to download source video: status %d", resp.StatusCode)
		}

		dlSize := resp.ContentLength
		if dlSize <= 0 {
			dlSize = fileSize
		}

		filename := path.Base(sourceURL)
		if filename == "" || filename == "." || filename == "/" {
			filename = "video.mp4"
		}

		result, compErr := s.cloudConvertSvc.CompressVideo(ctx, filename, resp.Body, dlSize)
		if compErr != nil {
			return domain.SubCourseVideo{}, fmt.Errorf("failed to compress video: %w", compErr)
		}
		defer result.Data.Close()

		uploadResult, err = s.vimeoSvc.UploadVideoFile(ctx, title, descStr, result.Data, result.FileSize)
	} else {
		uploadResult, err = s.vimeoSvc.CreatePullUpload(ctx, title, descStr, sourceURL, fileSize)
	}

	if err != nil {
		return domain.SubCourseVideo{}, fmt.Errorf("failed to upload to Vimeo: %w", err)
	}

	embedURL := vimeo.GenerateEmbedURL(uploadResult.VimeoID, &vimeo.EmbedOptions{
		Title:    true,
		Byline:   true,
		Portrait: true,
	})

	embedHTML := vimeo.GenerateIframeEmbed(uploadResult.VimeoID, 640, 360, nil)

	provider := string(domain.VideoHostProviderVimeo)
	vimeoStatus := "uploading"
	status := "DRAFT"

	return s.courseStore.CreateSubCourseVideo(
		ctx, subCourseID, title, description,
		uploadResult.Link,
		duration, resolution, instructorID, thumbnail, visibility, displayOrder, &status,
		&uploadResult.VimeoID, &embedURL, &embedHTML, &vimeoStatus, &provider,
	)
}

func (s *Service) CreateSubCourseVideoWithFileUpload(
	ctx context.Context,
	subCourseID int64,
	title string,
	description *string,
	filename string,
	fileData io.Reader,
	fileSize int64,
	duration int32,
	resolution *string,
	instructorID *string,
	thumbnail *string,
	visibility *string,
	displayOrder *int32,
) (domain.SubCourseVideo, error) {
	if s.vimeoSvc == nil {
		return domain.SubCourseVideo{}, fmt.Errorf("vimeo service is not configured")
	}

	descStr := ""
	if description != nil {
		descStr = *description
	}

	videoReader := fileData
	videoSize := fileSize

	if s.cloudConvertSvc != nil {
		result, err := s.cloudConvertSvc.CompressVideo(ctx, filename, fileData, fileSize)
		if err != nil {
			return domain.SubCourseVideo{}, fmt.Errorf("failed to compress video: %w", err)
		}
		defer result.Data.Close()
		videoReader = result.Data
		videoSize = result.FileSize
	}

	uploadResult, err := s.vimeoSvc.UploadVideoFile(ctx, title, descStr, videoReader, videoSize)
	if err != nil {
		return domain.SubCourseVideo{}, fmt.Errorf("failed to upload video file to Vimeo: %w", err)
	}

	embedURL := vimeo.GenerateEmbedURL(uploadResult.VimeoID, &vimeo.EmbedOptions{
		Title:    true,
		Byline:   true,
		Portrait: true,
	})

	embedHTML := vimeo.GenerateIframeEmbed(uploadResult.VimeoID, 640, 360, nil)

	provider := string(domain.VideoHostProviderVimeo)
	vimeoStatus := "uploading"
	status := "DRAFT"

	return s.courseStore.CreateSubCourseVideo(
		ctx, subCourseID, title, description,
		uploadResult.Link,
		duration, resolution, instructorID, thumbnail, visibility, displayOrder, &status,
		&uploadResult.VimeoID, &embedURL, &embedHTML, &vimeoStatus, &provider,
	)
}

// CreateSubCourseVideoFromVimeoID creates a video record from an existing Vimeo video
func (s *Service) CreateSubCourseVideoFromVimeoID(
	ctx context.Context,
	subCourseID int64,
	vimeoVideoID string,
	title string,
	description *string,
	displayOrder *int32,
	instructorID *string,
) (domain.SubCourseVideo, error) {
	if s.vimeoSvc == nil {
		return domain.SubCourseVideo{}, fmt.Errorf("vimeo service is not configured")
	}

	// Fetch video info from Vimeo
	info, err := s.vimeoSvc.GetVideoInfo(ctx, vimeoVideoID)
	if err != nil {
		return domain.SubCourseVideo{}, fmt.Errorf("failed to get Vimeo video info: %w", err)
	}

	// Use Vimeo data
	embedHTML := vimeo.GenerateIframeEmbed(vimeoVideoID, 640, 360, nil)
	provider := string(domain.VideoHostProviderVimeo)
	vimeoStatus := info.TranscodeStatus
	if vimeoStatus == "" {
		vimeoStatus = "available"
	}
	status := "DRAFT"
	duration := int32(info.Duration)
	resolution := fmt.Sprintf("%dx%d", info.Width, info.Height)
	thumbnail := info.ThumbnailURL

	return s.courseStore.CreateSubCourseVideo(
		ctx, subCourseID, title, description,
		info.Link, duration, &resolution, instructorID, &thumbnail, nil, displayOrder, &status,
		&vimeoVideoID, &info.EmbedURL, &embedHTML, &vimeoStatus, &provider,
	)
}

func (s *Service) GetSubCourseVideoByID(
	ctx context.Context,
	id int64,
) (domain.SubCourseVideo, error) {
	return s.courseStore.GetSubCourseVideoByID(ctx, id)
}

func (s *Service) GetVideosBySubCourse(
	ctx context.Context,
	subCourseID int64,
) ([]domain.SubCourseVideo, int64, error) {
	return s.courseStore.GetVideosBySubCourse(ctx, subCourseID)
}

func (s *Service) GetPublishedVideosBySubCourse(
	ctx context.Context,
	subCourseID int64,
) ([]domain.SubCourseVideo, error) {
	return s.courseStore.GetPublishedVideosBySubCourse(ctx, subCourseID)
}

func (s *Service) PublishSubCourseVideo(
	ctx context.Context,
	videoID int64,
) error {
	return s.courseStore.PublishSubCourseVideo(ctx, videoID)
}

func (s *Service) UpdateSubCourseVideo(
	ctx context.Context,
	id int64,
	title *string,
	description *string,
	videoURL *string,
	duration *int32,
	resolution *string,
	visibility *string,
	thumbnail *string,
	displayOrder *int32,
	status *string,
) error {
	return s.courseStore.UpdateSubCourseVideo(ctx, id, title, description, videoURL, duration, resolution, visibility, thumbnail, displayOrder, status)
}

func (s *Service) ArchiveSubCourseVideo(
	ctx context.Context,
	id int64,
) error {
	return s.courseStore.ArchiveSubCourseVideo(ctx, id)
}

func (s *Service) DeleteSubCourseVideo(
	ctx context.Context,
	id int64,
) error {
	return s.courseStore.DeleteSubCourseVideo(ctx, id)
}
