package store

import (
	"database/sql"
	"fmt"
	"git.yeij.top/AskaEth/Cyrene/pkg/logger"
	"time"
)

// File 文件元数据模型
type File struct {
	ID         string    `json:"id"`
	UserID     string    `json:"user_id"`
	Filename   string    `json:"filename"`
	StoredPath string    `json:"stored_path"`
	MimeType   string    `json:"mime_type"`
	Size       int64     `json:"size"`
	Hash       string    `json:"hash"`
	IsPublic   bool      `json:"is_public"`
	CreatedAt  time.Time `json:"created_at"`
}

// FileStore 文件元数据持久化存储
type FileStore struct {
	db *sql.DB
}

// NewFileStore 使用已有数据库连接初始化文件存储并自动建表
func NewFileStore(db *sql.DB) (*FileStore, error) {
	store := &FileStore{db: db}

	if err := store.migrate(); err != nil {
		return nil, fmt.Errorf("文件表迁移失败: %w", err)
	}

	logger.Println("[FileStore] 文件持久化存储已初始化")
	return store, nil
}

// migrate 自动创建文件表结构
func (s *FileStore) migrate() error {
	queries := []string{
		`CREATE TABLE IF NOT EXISTS files (
			id VARCHAR(36) PRIMARY KEY,
			user_id VARCHAR(255) NOT NULL,
			filename VARCHAR(500) NOT NULL,
			stored_path VARCHAR(1000) NOT NULL,
			mime_type VARCHAR(255) NOT NULL DEFAULT 'application/octet-stream',
			size BIGINT NOT NULL DEFAULT 0,
			hash VARCHAR(64) NOT NULL DEFAULT '',
			is_public BOOLEAN DEFAULT FALSE,
			created_at TIMESTAMPTZ DEFAULT NOW()
		)`,
		`CREATE INDEX IF NOT EXISTS idx_files_user_id ON files(user_id)`,
		`CREATE INDEX IF NOT EXISTS idx_files_hash ON files(hash)`,
		`CREATE INDEX IF NOT EXISTS idx_files_created_at ON files(user_id, created_at DESC)`,
	}

	for _, q := range queries {
		if _, err := s.db.Exec(q); err != nil {
			return fmt.Errorf("迁移SQL执行失败: %w\nSQL: %s", err, q)
		}
	}
	return nil
}

// CreateFile 创建文件元数据记录
func (s *FileStore) CreateFile(f *File) error {
	_, err := s.db.Exec(
		`INSERT INTO files (id, user_id, filename, stored_path, mime_type, size, hash, is_public, created_at)
		 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
		f.ID, f.UserID, f.Filename, f.StoredPath, f.MimeType, f.Size, f.Hash, f.IsPublic, f.CreatedAt,
	)
	if err != nil {
		return fmt.Errorf("创建文件记录失败: %w", err)
	}
	return nil
}

// GetFile 根据ID获取文件元数据
func (s *FileStore) GetFile(id string) (*File, error) {
	var f File
	err := s.db.QueryRow(
		`SELECT id, user_id, filename, stored_path, mime_type, size, hash, is_public, created_at
		 FROM files WHERE id = $1`,
		id,
	).Scan(&f.ID, &f.UserID, &f.Filename, &f.StoredPath, &f.MimeType, &f.Size, &f.Hash, &f.IsPublic, &f.CreatedAt)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, fmt.Errorf("查询文件失败: %w", err)
	}
	return &f, nil
}

// GetUserFiles 获取用户的所有文件，支持分页
func (s *FileStore) GetUserFiles(userID string, page, limit int) ([]File, int, error) {
	if page <= 0 {
		page = 1
	}
	if limit <= 0 || limit > 100 {
		limit = 20
	}
	offset := (page - 1) * limit

	// 获取总数
	var total int
	if err := s.db.QueryRow(
		`SELECT COUNT(*) FROM files WHERE user_id = $1`,
		userID,
	).Scan(&total); err != nil {
		return nil, 0, fmt.Errorf("查询文件总数失败: %w", err)
	}

	// 分页查询
	rows, err := s.db.Query(
		`SELECT id, user_id, filename, stored_path, mime_type, size, hash, is_public, created_at
		 FROM files WHERE user_id = $1
		 ORDER BY created_at DESC
		 LIMIT $2 OFFSET $3`,
		userID, limit, offset,
	)
	if err != nil {
		return nil, 0, fmt.Errorf("查询用户文件失败: %w", err)
	}
	defer rows.Close()

	var files []File
	for rows.Next() {
		var f File
		if err := rows.Scan(&f.ID, &f.UserID, &f.Filename, &f.StoredPath, &f.MimeType, &f.Size, &f.Hash, &f.IsPublic, &f.CreatedAt); err != nil {
			return nil, 0, fmt.Errorf("扫描文件行失败: %w", err)
		}
		files = append(files, f)
	}

	if files == nil {
		files = []File{}
	}
	return files, total, rows.Err()
}

// GetFileByHash 根据SHA256哈希查找文件（用于去重）
func (s *FileStore) GetFileByHash(hash string) (*File, error) {
	if hash == "" {
		return nil, nil
	}
	var f File
	err := s.db.QueryRow(
		`SELECT id, user_id, filename, stored_path, mime_type, size, hash, is_public, created_at
		 FROM files WHERE hash = $1
		 ORDER BY created_at ASC LIMIT 1`,
		hash,
	).Scan(&f.ID, &f.UserID, &f.Filename, &f.StoredPath, &f.MimeType, &f.Size, &f.Hash, &f.IsPublic, &f.CreatedAt)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, fmt.Errorf("按哈希查询文件失败: %w", err)
	}
	return &f, nil
}

// DeleteFile 删除文件元数据记录
func (s *FileStore) DeleteFile(id string) error {
	_, err := s.db.Exec(`DELETE FROM files WHERE id = $1`, id)
	if err != nil {
		return fmt.Errorf("删除文件记录失败: %w", err)
	}
	return nil
}
