<?php
/**
 * HuSNS - 附件管理服务
 *
 * @author  HYR
 * @QQ      281900864
 * @website https://huyourui.com
 * @license MIT
 */
class AttachmentService
{
    private $db;
    private $uploadPath;

    public function __construct()
    {
        $this->db = Database::getInstance();
        $this->uploadPath = ROOT_PATH . 'uploads' . DIRECTORY_SEPARATOR;
    }

    public function getUploadPath()
    {
        return $this->uploadPath;
    }

    /**
     * 获取所有附件列表
     */
    public function getAttachments($type = null, $page = 1, $perPage = 20, $usedStatus = null, $keyword = '')
    {
        $attachments = [];
        $total = 0;

        $types = $type ? [$type] : ['images', 'videos', 'attachments'];
        $typeCounts = [];

        foreach ($types as $t) {
            $count = $this->countFiles($this->uploadPath . $t, $usedStatus, $keyword);
            $typeCounts[$t] = $count;
            $total += $count;
        }

        $totalPages = $total > 0 ? ceil($total / $perPage) : 1;
        $page = max(1, min($page, $totalPages));
        $offset = ($page - 1) * $perPage;

        $currentIndex = 0;
        foreach ($types as $t) {
            $typeOffset = max(0, $offset - $currentIndex);
            $typeLimit = min($perPage - count($attachments), $typeCounts[$t] - $typeOffset);

            if ($typeLimit > 0) {
                $items = $this->scanDirectory($this->uploadPath . $t, $t, $usedStatus, $keyword, $typeOffset, $typeLimit);
                $attachments = array_merge($attachments, $items);
            }

            $currentIndex += $typeCounts[$t];

            if (count($attachments) >= $perPage) {
                break;
            }
        }

        usort($attachments, function($a, $b) {
            return $b['mtime'] - $a['mtime'];
        });

        return [
            'items' => $attachments,
            'total' => $total,
            'page' => $page,
            'totalPages' => $totalPages,
            'typeCounts' => $typeCounts
        ];
    }

    /**
     * 统计目录文件数量
     */
    private function countFiles($dir, $usedStatus, $keyword)
    {
        $count = 0;

        if (!is_dir($dir)) {
            return 0;
        }

        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($iterator as $file) {
            if ($file->isDir()) {
                continue;
            }

            $relativePath = str_replace($this->uploadPath, '', $file->getPathname());
            $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath);

            $usedInfo = $this->checkFileUsed($relativePath);
            $isUsed = $usedInfo['used'];

            if ($usedStatus !== null) {
                if ($usedStatus == 0 && $isUsed) continue;
                if ($usedStatus == 1 && !$isUsed) continue;
            }

            if ($keyword) {
                if (stripos($file->getFilename(), $keyword) === false &&
                    stripos($relativePath, $keyword) === false) {
                    continue;
                }
            }

            $count++;
        }

        return $count;
    }

    /**
     * 扫描目录获取附件
     */
    private function scanDirectory($dir, $type, $usedStatus, $keyword, $offset, $limit)
    {
        $items = [];
        $currentIndex = 0;

        if (!is_dir($dir)) {
            return $items;
        }

        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($iterator as $file) {
            if ($file->isDir()) {
                continue;
            }

            $relativePath = str_replace($this->uploadPath, '', $file->getPathname());
            $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath);

            $usedInfo = $this->checkFileUsed($relativePath);
            $isUsed = $usedInfo['used'];

            if ($usedStatus !== null) {
                if ($usedStatus == 0 && $isUsed) continue;
                if ($usedStatus == 1 && !$isUsed) continue;
            }

            if ($keyword) {
                if (stripos($file->getFilename(), $keyword) === false &&
                    stripos($relativePath, $keyword) === false) {
                    continue;
                }
            }

            if ($currentIndex < $offset) {
                $currentIndex++;
                continue;
            }

            if (count($items) >= $limit) {
                break;
            }

            $ext = strtolower($file->getExtension());
            $mimeType = $this->getMimeType($file->getPathname());

            $items[] = [
                'id' => md5($relativePath),
                'path' => $relativePath,
                'filename' => $file->getFilename(),
                'type' => $type,
                'ext' => $ext,
                'size' => $file->getSize(),
                'mtime' => $file->getMTime(),
                'is_used' => $isUsed,
                'used_info' => $usedInfo,
                'mime_type' => $mimeType
            ];

            $currentIndex++;
        }

        return $items;
    }

    /**
     * 检查文件是否被使用
     */
    public function checkFileUsed($path)
    {
        $pathNormalized = trim(str_replace('\\', '/', $path));
        $pathWithoutPrefix = preg_replace('/^(images|videos|attachments)\//', '', $pathNormalized);

        $searchPaths = array_unique([$pathNormalized, $pathWithoutPrefix]);

        $post = $this->findPostWithAttachment($searchPaths);

        if ($post) {
            return [
                'used' => true,
                'post_id' => $post['id'],
                'user_id' => $post['user_id']
            ];
        }

        return ['used' => false, 'post_id' => null, 'user_id' => null];
    }

    private function findPostWithAttachment($paths)
    {
        foreach ($paths as $searchPath) {
            // 获取文件名（去掉路径）
            $filename = basename($searchPath);
            
            $conditions = [];
            $params = [];

            // 直接搜索文件名，这样更可靠
            $conditions[] = "images LIKE ?";
            $params[] = '%' . $filename . '%';

            $conditions[] = "attachments LIKE ?";
            $params[] = '%' . $filename . '%';

            $conditions[] = "videos LIKE ?";
            $params[] = '%' . $filename . '%';

            $whereClause = implode(' OR ', $conditions);
            $sql = "SELECT id, user_id FROM " . DB_PREFIX . "posts WHERE status = 1 AND ({$whereClause}) LIMIT 1";

            $post = $this->db->fetch($sql, $params);
            if ($post) {
                return $post;
            }
        }

        return null;
    }

    /**
     * 获取MIME类型
     */
    private function getMimeType($filePath)
    {
        if (function_exists('finfo_open')) {
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
            $mime = finfo_file($finfo, $filePath);
            finfo_close($finfo);
            return $mime;
        }
        return 'application/octet-stream';
    }

    /**
     * 删除单个附件
     */
    public function deleteFile($path)
    {
        $fullPath = $this->uploadPath . $path;

        if (!file_exists($fullPath)) {
            return false;
        }

        if (strpos(realpath($fullPath), realpath($this->uploadPath)) !== 0) {
            return false;
        }

        return unlink($fullPath);
    }

    /**
     * 批量删除未使用的附件
     */
    public function deleteUnused($type = null, $olderThanDays = 0)
    {
        $count = 0;
        $types = $type ? [$type] : ['images', 'videos', 'attachments'];

        foreach ($types as $t) {
            $dir = $this->uploadPath . $t;
            if (!is_dir($dir)) continue;

            $iterator = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
                RecursiveIteratorIterator::SELF_FIRST
            );

            $cutoffTime = $olderThanDays > 0 ? time() - ($olderThanDays * 86400) : 0;

            foreach ($iterator as $file) {
                if ($file->isDir()) continue;

                $relativePath = str_replace($this->uploadPath, '', $file->getPathname());
                $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath);

                $usedInfo = $this->checkFileUsed($relativePath);

                if (!$usedInfo['used']) {
                    if ($olderThanDays > 0 && $file->getMTime() > $cutoffTime) {
                        continue;
                    }

                    if ($this->deleteFile($relativePath)) {
                        $count++;
                    }
                }
            }
        }

        return $count;
    }

    /**
     * 获取附件统计信息
     */
    public function getStats()
    {
        $stats = [
            'total_count' => 0,
            'total_size' => 0,
            'used_count' => 0,
            'unused_count' => 0,
            'by_type' => [
                'images' => ['count' => 0, 'size' => 0, 'used' => 0, 'unused' => 0],
                'videos' => ['count' => 0, 'size' => 0, 'used' => 0, 'unused' => 0],
                'attachments' => ['count' => 0, 'size' => 0, 'used' => 0, 'unused' => 0]
            ]
        ];

        $types = ['images', 'videos', 'attachments'];

        foreach ($types as $type) {
            $dir = $this->uploadPath . $type;
            if (!is_dir($dir)) continue;

            $iterator = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
                RecursiveIteratorIterator::SELF_FIRST
            );

            foreach ($iterator as $file) {
                if ($file->isDir()) continue;

                $relativePath = str_replace($this->uploadPath, '', $file->getPathname());
                $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath);

                $usedInfo = $this->checkFileUsed($relativePath);

                $stats['total_count']++;
                $stats['total_size'] += $file->getSize();
                $stats['by_type'][$type]['count']++;
                $stats['by_type'][$type]['size'] += $file->getSize();

                if ($usedInfo['used']) {
                    $stats['used_count']++;
                    $stats['by_type'][$type]['used']++;
                } else {
                    $stats['unused_count']++;
                    $stats['by_type'][$type]['unused']++;
                }
            }
        }

        return $stats;
    }

    /**
     * 格式化文件大小
     */
    public static function formatSize($bytes)
    {
        if ($bytes < 1024) {
            return $bytes . ' B';
        } elseif ($bytes < 1024 * 1024) {
            return round($bytes / 1024, 1) . ' KB';
        } elseif ($bytes < 1024 * 1024 * 1024) {
            return round($bytes / (1024 * 1024), 1) . ' MB';
        } else {
            return round($bytes / (1024 * 1024 * 1024), 2) . ' GB';
        }
    }
}