package filemanager

import (
	"context"
	"errors"
	"io"
	"time"
)

const (
	SystemRootFolderName = "__system_root_files__"
)

var (
	ErrDuplicateName                  = errors.New("duplicate name in target folder")
	ErrInvalidMove                    = errors.New("invalid folder move")
	ErrFolderNotFound                 = errors.New("folder not found")
	ErrFileNotFound                   = errors.New("file not found")
	ErrFileAlreadyFinalized           = errors.New("file already finalized")
	ErrFileNotEligibleForFinalize     = errors.New("file is not eligible for finalize")
	ErrInvalidFileStatusTransition    = errors.New("invalid file status transition")
	ErrFileStatusConflict             = errors.New("file status conflict")
	ErrStorageUnavailable             = errors.New("storage unavailable")
	ErrFolderNotEmpty                 = errors.New("folder is not empty")
	ErrFolderNotInTrash               = errors.New("folder is not in trash")
	ErrFileNotInTrash                 = errors.New("file is not in trash")
	ErrInvalidName                    = errors.New("invalid name")
	ErrReservedName                   = errors.New("reserved name")
	ErrFileTooLarge                   = errors.New("file too large")
	ErrFileMimeTypeNotAllowed         = errors.New("file mime type is not allowed")
	ErrFileExtensionNotAllowed        = errors.New("file extension is not allowed")
	ErrEmptyFileNotAllowed            = errors.New("empty file is not allowed")
	ErrFileNameTooLong                = errors.New("file name exceeds maximum length")
	ErrFileProcessingQueueDisabled    = errors.New("file processing queue is not configured")
	ErrUploadIntentRepositoryDisabled = errors.New("file upload intent repository is not configured")
	ErrUploadIntentNotFound           = errors.New("upload intent not found")
	ErrUploadIntentExpired            = errors.New("upload intent is expired")
	ErrUploadIntentAlreadyComplete    = errors.New("upload intent already completed")
	ErrUploadIntentStatusConflict     = errors.New("upload intent status conflict")
	ErrUploadObjectNotFound           = errors.New("uploaded object not found in storage")
	ErrUploadObjectMismatch           = errors.New("uploaded object does not match upload intent")
	ErrAttachmentRepositoryDisabled   = errors.New("attachment repository is not configured")
	ErrAttachmentNotFound             = errors.New("attachment not found")
	ErrAttachmentAlreadyExists        = errors.New("attachment already exists for this reference")
	ErrAttachmentRefRequired          = errors.New("attachment ref_type and ref_id are required")
	ErrFileNotReadyForAttachment      = errors.New("file is not ready for attachment")
)

type FileUploadPolicy struct {
	MaxFileSizeBytes  int64
	AllowedMimeTypes  []string
	AllowedExtensions []string
	AllowEmptyFile    bool
	MaxFilenameLength int
}

type FileProcessingJob struct {
	JobID      string
	FileUUID   string
	Bucket     string
	ObjectKey  string
	UploadedBy string
	MimeType   string
	SizeBytes  int64
	TraceID    string
	RequestID  string
}

type FileProcessingQueue interface {
	Enqueue(ctx context.Context, job FileProcessingJob) error
}

type CreateFolderParams struct {
	Name     string
	ParentID []byte
	ActorID  []byte
}

type MoveFolderParams struct {
	Name           *string
	ParentID       []byte
	ParentProvided bool
	ActorID        []byte
}

type UploadFileParams struct {
	Name        string
	ContentType string
	SizeBytes   int64
	Body        io.Reader
	ActorID     []byte
	IsTemplate  bool
}

type RequestFileUploadIntentParams struct {
	Name        string
	ContentType string
	SizeBytes   int64
	ActorID     []byte
}

type FileUploadIntentGrant struct {
	UploadIntentID []byte
	Bucket         string
	ObjectKey      string
	Name           string
	MimeType       string
	SizeBytes      int64
	Method         string
	UploadURL      string
	Headers        map[string]string
	ExpiresAt      time.Time
}

type CompleteFileUploadIntentParams struct {
	UploadIntentID []byte
	ActorID        []byte
}

type CancelFileUploadIntentParams struct {
	UploadIntentID []byte
	ActorID        []byte
}

type CreateFileFromUploadParams struct {
	UploadFileID   []byte
	FolderID       []byte
	FolderProvided bool
	Name           *string
	ActorID        []byte
	IsTemplate     bool
}

type CreateFileFromUploadIntentParams struct {
	UploadIntentID []byte
	FolderID       []byte
	FolderProvided bool
	Name           string
	ActorID        []byte
	IsTemplate     bool
}

type BulkFileNodeResult struct {
	Index int
	File  *File
	Err   error
}

type MoveFileParams struct {
	Name           *string
	FolderID       []byte
	FolderProvided bool
	ActorID        []byte
}

type CreateAttachmentParams struct {
	FileID    []byte
	RefType   string
	RefID     string
	Category  *string
	SortOrder int
	IsPrimary bool
	ActorID   []byte
}

type ListAttachmentsParams struct {
	RefType  string
	RefID    string
	Category *string
	Sort     string
	Limit    int
	Offset   int
}

type FileCleanupStats struct {
	Scanned int
	Deleted int
	Skipped int
	Failed  int
	DryRun  bool
}

// LifecycleManager is an optional extension implemented by concrete services
// to expose file lifecycle transitions without widening the base Service
// interface used by existing handlers/tests.
type LifecycleManager interface {
	MarkFileActive(ctx context.Context, fileID []byte, actorID []byte) error
	ReconcileFileLifecycle(ctx context.Context, fileID []byte, actorID []byte) error
	CleanupOrphanPendingFiles(ctx context.Context, now time.Time, gracePeriod time.Duration, limit int, dryRun bool) (FileCleanupStats, error)
}

type Service interface {
	SetObjectStorage(storage ObjectStorage)
	SetUploadPolicy(policy FileUploadPolicy)
	SetFileProcessingQueue(fileQueue FileProcessingQueue)
	SetFileUploadIntentRepository(repo FileUploadIntentRepository)
	RequestFileUploadIntent(ctx context.Context, params RequestFileUploadIntentParams) (*FileUploadIntentGrant, error)
	CompleteFileUploadIntent(ctx context.Context, params CompleteFileUploadIntentParams) (*File, error)
	CancelFileUploadIntent(ctx context.Context, params CancelFileUploadIntentParams) error
	CreateFileNodeFromUploadIntent(ctx context.Context, params CreateFileFromUploadIntentParams) (*File, error)
	GetOrCreateSystemRootFolder(ctx context.Context) (*Folder, error)
	CreateFolderNode(ctx context.Context, params CreateFolderParams) (*Folder, error)
	MoveFolderNode(ctx context.Context, id []byte, params MoveFolderParams) (*Folder, error)
	UploadFileNode(ctx context.Context, params UploadFileParams) (*File, error)
	CreateFileNodeFromUpload(ctx context.Context, params CreateFileFromUploadParams) (*File, error)
	UploadFileNodesBulk(ctx context.Context, params []UploadFileParams) []BulkFileNodeResult
	CreateFileNodesFromUploadBulk(ctx context.Context, params []CreateFileFromUploadParams) []BulkFileNodeResult
	MoveFileNode(ctx context.Context, id []byte, params MoveFileParams) (*File, error)
	PurgeFolderNode(ctx context.Context, id []byte) error
	PurgeFileNode(ctx context.Context, id []byte) error
	ListNodesByParent(ctx context.Context, parentID []byte) ([]Folder, []File, error)
	SearchNodes(ctx context.Context, query string) ([]Folder, []File, error)
	ListTrashNodes(ctx context.Context) ([]Folder, []File, error)

	CreateFolder(ctx context.Context, row *Folder) error
	UpdateFolder(ctx context.Context, row *Folder) error
	DeleteFolder(ctx context.Context, id []byte, deletedBy []byte, purgeAt *time.Time) error
	RestoreFolder(ctx context.Context, id []byte, targetParentID []byte, targetProvided bool, restoredBy []byte) error
	PurgeFolder(ctx context.Context, id []byte) error
	GetFolderByID(ctx context.Context, id []byte) (*Folder, error)
	GetFolderByIDAny(ctx context.Context, id []byte) (*Folder, error)
	GetFolderByParentAndName(ctx context.Context, parentID []byte, nameNormalized string) (*Folder, error)
	ListFoldersByParent(ctx context.Context, parentID []byte, sort string, limit, offset int) ([]Folder, int64, error)
	ListTrashFoldersByParent(ctx context.Context, parentID []byte, sort string, limit, offset int) ([]Folder, int64, error)

	CreateFile(ctx context.Context, row *File) error
	UpdateFile(ctx context.Context, row *File) error
	DeleteFile(ctx context.Context, id []byte, deletedBy []byte, purgeAt *time.Time) error
	RestoreFile(ctx context.Context, id []byte, targetFolderID []byte, targetProvided bool, restoredBy []byte) error
	PurgeFile(ctx context.Context, id []byte) error
	GetFileByID(ctx context.Context, id []byte) (*File, error)
	GetFileByIDAny(ctx context.Context, id []byte) (*File, error)
	GetFileByObjectKey(ctx context.Context, objectKey string) (*File, error)
	GetFileByFolderAndName(ctx context.Context, folderID []byte, nameNormalized string) (*File, error)
	ListFilesByFolder(ctx context.Context, folderID []byte, sort string, limit, offset int) ([]File, int64, error)
	ListTrashFilesByFolder(ctx context.Context, folderID []byte, sort string, limit, offset int) ([]File, int64, error)
	CreateAttachment(ctx context.Context, params CreateAttachmentParams) (*Attachment, error)
	GetAttachmentByID(ctx context.Context, id []byte) (*Attachment, error)
	ListAttachmentsByReference(ctx context.Context, params ListAttachmentsParams) ([]Attachment, int64, error)
	DeleteAttachment(ctx context.Context, id []byte) error
	ListEditedWBFilesByTakeoverID(ctx context.Context, takeoverID []byte) ([]File, error)
}
