import { Injectable, Logger } from '@nestjs/common';
import { ConfigService as NestConfigService } from '@nestjs/config';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { PlatformConfig } from '@/entities/platform-config.entity';
import * as fs from 'fs';
import * as path from 'path';
import { v4 as uuidv4 } from 'uuid';

export type StorageProvider = 'local' | 'tencent_cos' | 'aliyun_oss';

export interface UploadResult {
  url: string;
  filename: string;
  originalname: string;
  size: number;
}

@Injectable()
export class UploadService {
  private readonly logger = new Logger(UploadService.name);

  constructor(
    @InjectRepository(PlatformConfig)
    private configRepo: Repository<PlatformConfig>,
    private nestConfigService: NestConfigService,
  ) {}

  async getStorageProvider(): Promise<StorageProvider> {
    const config = await this.configRepo.findOne({ where: { configKey: 'storage_provider' } });
    return (config?.configValue as StorageProvider) || 'local';
  }

  async upload(file: Express.Multer.File): Promise<UploadResult> {
    const provider = await this.getStorageProvider();
    this.logger.log(`上传文件: ${file.originalname}, 存储方式: ${provider}`);

    switch (provider) {
      case 'tencent_cos':
        return this.uploadTencentCos(file);
      case 'aliyun_oss':
        return this.uploadAliyunOss(file);
      default:
        return this.uploadLocal(file);
    }
  }

  private async uploadLocal(file: Express.Multer.File): Promise<UploadResult> {
    let uploadDir = './uploads';
    const dirConfig = await this.configRepo.findOne({ where: { configKey: 'storage_local_path' } });
    if (dirConfig?.configValue) uploadDir = dirConfig.configValue;

    if (!fs.existsSync(uploadDir)) {
      fs.mkdirSync(uploadDir, { recursive: true });
    }

    const ext = path.extname(file.originalname) || '.jpg';
    const filename = `${uuidv4()}${ext}`;
    const filepath = path.join(uploadDir, filename);

    fs.writeFileSync(filepath, file.buffer);

    return {
      url: `/uploads/${filename}`,
      filename,
      originalname: file.originalname,
      size: file.size,
    };
  }

  private async uploadTencentCos(file: Express.Multer.File): Promise<UploadResult> {
    try {
      // 动态导入，避免未安装时报错
      const COS = (await import('cos-nodejs-sdk-v5')).default;
      const configs = await this.getStorageConfigs('storage_cos_');
      const cos = new COS({
        SecretId: configs['secret_id'],
        SecretKey: configs['secret_key'],
      });

      const ext = path.extname(file.originalname) || '.jpg';
      const filename = `${uuidv4()}${ext}`;
      const key = `uploads/${filename}`;

      await new Promise<void>((resolve, reject) => {
        cos.putObject(
          {
            Bucket: configs['bucket'],
            Region: configs['region'],
            Key: key,
            Body: file.buffer,
          },
          (err) => (err ? reject(err) : resolve()),
        );
      });

      return {
        url: `https://${configs['bucket']}.cos.${configs['region']}.myqcloud.com/${key}`,
        filename,
        originalname: file.originalname,
        size: file.size,
      };
    } catch (err: any) {
      if (err.code === 'MODULE_NOT_FOUND') {
        throw new Error('腾讯云COS SDK未安装，请运行: pnpm add cos-nodejs-sdk-v5');
      }
      throw err;
    }
  }

  private async uploadAliyunOss(file: Express.Multer.File): Promise<UploadResult> {
    try {
      const OSS = (await import('ali-oss')).default;
      const configs = await this.getStorageConfigs('storage_oss_');

      const client = new OSS({
        region: configs['region'],
        accessKeyId: configs['access_key_id'],
        accessKeySecret: configs['access_key_secret'],
        bucket: configs['bucket'],
      });

      const ext = path.extname(file.originalname) || '.jpg';
      const filename = `${uuidv4()}${ext}`;
      const key = `uploads/${filename}`;

      await client.put(key, file.buffer);

      return {
        url: `https://${configs['bucket']}.${configs['region']}.aliyuncs.com/${key}`,
        filename,
        originalname: file.originalname,
        size: file.size,
      };
    } catch (err: any) {
      if (err.code === 'MODULE_NOT_FOUND') {
        throw new Error('阿里云OSS SDK未安装，请运行: pnpm add ali-oss');
      }
      throw err;
    }
  }

  private async getStorageConfigs(prefix: string): Promise<Record<string, string>> {
    const configs = await this.configRepo.find();
    const result: Record<string, string> = {};
    for (const c of configs) {
      if (c.configKey.startsWith(prefix)) {
        const key = c.configKey.replace(prefix, '');
        result[key] = c.configValue;
      }
    }
    return result;
  }

  async getStorageConfig(): Promise<Record<string, string>> {
    const configs = await this.configRepo.find();
    const result: Record<string, string> = {};
    for (const c of configs) {
      if (c.configKey.startsWith('storage_')) {
        result[c.configKey] = c.configValue;
      }
    }
    return result;
  }

  async updateStorageConfig(configs: Record<string, string>): Promise<void> {
    for (const [key, value] of Object.entries(configs)) {
      if (!key.startsWith('storage_')) continue;
      let config = await this.configRepo.findOne({ where: { configKey: key } });
      if (config) {
        config.configValue = value;
      } else {
        config = this.configRepo.create({ configKey: key, configValue: value });
      }
      await this.configRepo.save(config);
    }
  }
}
