<?php

declare(strict_types=1);

namespace Kylin\Export\Services;

use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Storage;

/**
 * 导出文件加密服务
 *
 * 依据《个人信息保护法》第五十一条：
 * 导出文件包含个人信息时需加密存储。
 *
 * 依据《数据安全法》第二十七条：
 * 开展数据处理活动应当加强风险监测，发现数据安全缺陷时应当立即采取补救措施。
 *
 * 使用方式：
 *   $encrypted = ExportEncryptor::encrypt($filePath);
 *   $decrypted = ExportEncryptor::decrypt($encryptedPath);
 */
final class ExportEncryptor
{
    /**
     * 加密导出文件
     *
     * @param string $filePath 原始文件路径
     * @param string|null $password 加密密码（可选，默认使用 APP_KEY）
     * @return string 加密后的文件路径
     */
    public static function encrypt(string $filePath, ?string $password = null): string
    {
        if (! file_exists($filePath)) {
            throw new \InvalidArgumentException("文件不存在：{$filePath}");
        }

        $content = file_get_contents($filePath);
        if ($content === false) {
            throw new \RuntimeException("无法读取文件：{$filePath}");
        }

        $password ??= config('app.key');
        $encrypted = openssl_encrypt($content, 'aes-256-cbc', $password, 0, self::getIv($password));

        if ($encrypted === false) {
            throw new \RuntimeException("文件加密失败：{$filePath}");
        }

        $encryptedPath = $filePath . '.enc';
        file_put_contents($encryptedPath, $encrypted);

        logger()->info('导出文件已加密', [
            'original' => basename($filePath),
            'encrypted' => basename($encryptedPath),
            'operator' => auth()->user()?->name ?? '系统',
            'timestamp' => now()->toDateTimeString(),
        ]);

        return $encryptedPath;
    }

    /**
     * 解密导出文件
     *
     * @param string $encryptedPath 加密文件路径
     * @param string|null $password 解密密码
     * @return string 解密后的内容
     */
    public static function decrypt(string $encryptedPath, ?string $password = null): string
    {
        if (! file_exists($encryptedPath)) {
            throw new \InvalidArgumentException("加密文件不存在：{$encryptedPath}");
        }

        $content = file_get_contents($encryptedPath);
        if ($content === false) {
            throw new \RuntimeException("无法读取加密文件：{$encryptedPath}");
        }

        $password ??= config('app.key');
        $decrypted = openssl_decrypt($content, 'aes-256-cbc', $password, 0, self::getIv($password));

        if ($decrypted === false) {
            throw new \RuntimeException("文件解密失败，可能密码错误或文件已损坏：{$encryptedPath}");
        }

        return $decrypted;
    }

    /**
     * 加密文件并返回流式下载响应
     *
     * 不落盘解密，直接输出解密后的文件内容。
     *
     * @param string $encryptedPath 加密文件路径
     * @param string $filename 下载文件名
     * @param string $contentType 内容类型
     * @return \Symfony\Component\HttpFoundation\StreamedResponse
     */
    public static function streamDecrypt(string $encryptedPath, string $filename, string $contentType = 'application/octet-stream'): \Symfony\Component\HttpFoundation\StreamedResponse
    {
        return response()->streamDownload(function () use ($encryptedPath) {
            echo self::decrypt($encryptedPath);
        }, $filename, [
            'Content-Type' => $contentType,
            'Cache-Control' => 'no-store, no-cache, must-revalidate',
        ]);
    }

    /**
     * 判断文件是否已加密
     */
    public static function isEncrypted(string $filePath): bool
    {
        return str_ends_with($filePath, '.enc');
    }

    /**
     * 获取加密后的文件路径
     */
    public static function encryptedPath(string $filePath): string
    {
        return $filePath . '.enc';
    }

    /**
     * 生成初始化向量
     */
    private static function getIv(string $password): string
    {
        // 基于密码生成固定的 16 字节 IV
        return substr(hash('sha256', $password, true), 0, 16);
    }

    /**
     * 合规声明
     */
    public static function complianceNotice(): string
    {
        return '本文件加密服务遵循《个人信息保护法》第五十一条和《数据安全法》第二十七条。';
    }
}