package storage_controller

import (
	"MediaTools/internal/errs"
	"MediaTools/internal/schemas/storage"
	"io"
	"iter"

	"github.com/sirupsen/logrus"
)

func GetDetail(path storage.StoragePath) (*storage.StorageFileInfo, error) {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(path.GetStorageType())
	if !exists {
		return nil, errs.ErrStorageProviderNotFound
	}
	return provider.GetDetail(path.GetPath())
}

func Exist(path storage.StoragePath) (bool, error) {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(path.GetStorageType())
	if !exists {
		return false, errs.ErrStorageProviderNotFound
	}
	return provider.Exist(path.GetPath())
}

func Mkdir(path storage.StoragePath) error {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(path.GetStorageType())
	if !exists {
		return errs.ErrStorageProviderNotFound
	}
	return provider.Mkdir(path.GetPath())
}

func Rename(path storage.StoragePath, newName string) error {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(path.GetStorageType())
	if !exists {
		return errs.ErrStorageProviderNotFound
	}
	err := provider.Rename(path.GetPath(), newName)
	switch err {
	case nil:
		return nil
	case errs.ErrStorageProvideNoSupport: // 如果不支持重命名，则尝试使用移动的方式
		return provider.Move(path.GetPath(), path.Parent().Join(newName).GetPath())
	default:
		return err
	}
}

func Delete(path storage.StoragePath) error {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(path.GetStorageType())
	if !exists {
		return errs.ErrStorageProviderNotFound
	}
	return provider.Delete(path.GetPath())
}

func CreateFile(path storage.StoragePath, reader io.Reader) error {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(path.GetStorageType())
	if !exists {
		return errs.ErrStorageProviderNotFound
	}
	return provider.CreateFile(path.GetPath(), reader)
}

func ReadFile(path storage.StoragePath) (io.ReadCloser, error) {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(path.GetStorageType())
	if !exists {
		return nil, errs.ErrStorageProviderNotFound
	}
	return provider.ReadFile(path.GetPath())
}

func List(dir storage.StoragePath) (iter.Seq2[storage.StorageEntry, error], error) {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(dir.GetStorageType())
	if !exists {
		return nil, errs.ErrStorageProviderNotFound
	}
	entries, err := provider.List(dir.GetPath())
	if err != nil {
		logrus.Warningf("列出目录内容失败: %s, 错误: %v", dir.GetPath(), err)
		return nil, err
	}

	return func(yield func(storage.StorageEntry, error) bool) {
		for entry, err := range entries {
			if err != nil {
				if !yield(nil, err) {
					return // 如果迭代器被中断，则退出
				}
				continue
			}
			if !yield(entry, nil) {
				return // 如果迭代器被中断，则退出
			}
		}
	}, nil
}

func ListRoot(storageType storage.StorageType) (iter.Seq2[storage.StorageEntry, error], error) {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(storageType)
	if !exists {
		return nil, errs.ErrStorageProviderNotFound
	}
	entries, err := provider.ListRoot()
	if err != nil {
		logrus.Warningf("列出根目录内容失败, 错误: %v", err)
		return nil, err
	}
	return func(yield func(storage.StorageEntry, error) bool) {
		for entry, err := range entries {
			if err != nil {
				if !yield(nil, err) {
					return // 如果迭代器被中断，则退出
				}
				continue
			}
			if !yield(entry, nil) {
				return // 如果迭代器被中断，则退出
			}
		}
	}, nil
}

func Copy(srcPath storage.StoragePath, dstPath storage.StoragePath) error {
	lock.RLock()
	defer lock.RUnlock()

	srcProvider, exists := getStorageProvider(srcPath.GetStorageType())
	if !exists {
		return errs.ErrStorageProviderNotFound
	}
	if srcPath.GetStorageType() != dstPath.GetStorageType() {
		reader, err := srcProvider.ReadFile(srcPath.GetPath())
		if err != nil {
			return err
		}
		defer reader.Close()
		return CreateFile(dstPath, reader)
	}
	return srcProvider.Copy(srcPath.GetPath(), dstPath.GetPath())
}

func Move(srcPath storage.StoragePath, dstPath storage.StoragePath) error {
	lock.RLock()
	defer lock.RUnlock()

	srcProvider, exists := getStorageProvider(srcPath.GetStorageType())
	if !exists {
		return errs.ErrStorageProviderNotFound
	}
	if srcPath.GetStorageType() != dstPath.GetStorageType() {
		reader, err := srcProvider.ReadFile(srcPath.GetPath())
		if err != nil {
			return err
		}
		defer reader.Close()
		err = CreateFile(dstPath, reader)
		if err != nil {
			return err
		}
		return srcProvider.Delete(srcPath.GetPath())
	}
	return srcProvider.Move(srcPath.GetPath(), dstPath.GetPath())
}

func Link(srcPath storage.StoragePath, dstPath storage.StoragePath) error {
	lock.RLock()
	defer lock.RUnlock()

	if srcPath.GetStorageType() != dstPath.GetStorageType() {
		return errs.ErrStorageProvideNoSupport
	}

	provider, exists := getStorageProvider(srcPath.GetStorageType())
	if !exists {
		return errs.ErrStorageProviderNotFound
	}
	return provider.Link(srcPath.GetPath(), dstPath.GetPath())
}

func SoftLink(srcPath storage.StoragePath, dstPath storage.StoragePath) error {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(srcPath.GetStorageType())
	if !exists {
		return errs.ErrStorageProviderNotFound
	}
	return provider.SoftLink(srcPath.GetPath(), dstPath.GetPath())
}

func IterFiles(dir storage.StoragePath) (iter.Seq2[storage.StorageEntry, error], error) {
	lock.RLock()
	defer lock.RUnlock()

	provider, exists := getStorageProvider(dir.GetStorageType())
	if !exists {
		return nil, errs.ErrStorageProviderNotFound
	}

	// 验证目录是否存在
	dirExists, err := provider.Exist(dir.GetPath())
	if err != nil {
		return nil, err
	}
	if !dirExists {
		return nil, errs.ErrStorageProviderNotFound
	}

	// 验证路径是否为目录
	dirInfo, err := provider.GetDetail(dir.GetPath())
	if err != nil {
		return nil, err
	}
	if dirInfo.Type != storage.FileTypeDirectory {
		return nil, errs.ErrNotADirectory
	}

	return func(yield func(storage.StorageEntry, error) bool) {
		iterFilesRecursive(provider, dir.GetPath(), yield)
	}, nil
}

// iterFilesRecursive 递归遍历目录中的所有文件
func iterFilesRecursive(provider storage.StorageProvider, dirPath string, yield func(storage.StorageEntry, error) bool) {
	entries, err := provider.List(dirPath)
	if err != nil {
		if !yield(nil, err) {
			return
		}
		return
	}

	for entry, err := range entries {
		if err != nil {
			if !yield(nil, err) { // 如果迭代器被中断，则退出
				return
			}
			continue
		}

		if entry.GetFileType() == storage.FileTypeDirectory { // 如果是目录，递归遍历
			iterFilesRecursive(provider, entry.GetPath(), yield)
		} else { // 如果是文件，yield 返回
			if !yield(entry, nil) {
				return
			}
		}
	}
}
