import Store from 'electron-store';
import * as crypto from 'crypto';
import { v4 as uuidv4 } from 'uuid';

// Share 数据结构
export interface ShareEntry {
  id: string;
  sessionId: string;
  walletName: string;
  partyId: string;
  partyIndex: number;
  threshold: {
    t: number;
    n: number;
  };
  publicKey: string;
  encryptedShare: string;
  createdAt: string;
  lastUsedAt?: string;
  metadata: {
    participants: Array<{
      partyId: string;
      name: string;
    }>;
  };
}

// 存储的数据结构
interface StoreSchema {
  version: string;
  shares: ShareEntry[];
  settings: {
    messageRouterHost: string;
    messageRouterPort: number;
    autoBackup: boolean;
  };
}

// 加密配置
const ALGORITHM = 'aes-256-gcm';
const KEY_LENGTH = 32;
const IV_LENGTH = 16;
const SALT_LENGTH = 32;
const TAG_LENGTH = 16;
const ITERATIONS = 100000;

/**
 * 安全存储类 - 本地加密存储 share
 */
export class SecureStorage {
  private store: Store<StoreSchema>;

  constructor() {
    this.store = new Store<StoreSchema>({
      name: 'service-party-data',
      defaults: {
        version: '1.0.0',
        shares: [],
        settings: {
          messageRouterHost: 'localhost',
          messageRouterPort: 9092,
          autoBackup: false,
        },
      },
      encryptionKey: 'service-party-app-encryption-key', // 基础加密，share 数据还有额外加密
    });
  }

  /**
   * 从密码派生密钥
   */
  private deriveKey(password: string, salt: Buffer): Buffer {
    return crypto.pbkdf2Sync(password, salt, ITERATIONS, KEY_LENGTH, 'sha256');
  }

  /**
   * 加密数据
   */
  private encrypt(data: string, password: string): string {
    const salt = crypto.randomBytes(SALT_LENGTH);
    const key = this.deriveKey(password, salt);
    const iv = crypto.randomBytes(IV_LENGTH);

    const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
    let encrypted = cipher.update(data, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    const tag = cipher.getAuthTag();

    // 格式: salt(hex) + iv(hex) + tag(hex) + encrypted(hex)
    return salt.toString('hex') + iv.toString('hex') + tag.toString('hex') + encrypted;
  }

  /**
   * 解密数据
   */
  private decrypt(encryptedData: string, password: string): string {
    const salt = Buffer.from(encryptedData.slice(0, SALT_LENGTH * 2), 'hex');
    const iv = Buffer.from(encryptedData.slice(SALT_LENGTH * 2, SALT_LENGTH * 2 + IV_LENGTH * 2), 'hex');
    const tag = Buffer.from(encryptedData.slice(SALT_LENGTH * 2 + IV_LENGTH * 2, SALT_LENGTH * 2 + IV_LENGTH * 2 + TAG_LENGTH * 2), 'hex');
    const encrypted = encryptedData.slice(SALT_LENGTH * 2 + IV_LENGTH * 2 + TAG_LENGTH * 2);

    const key = this.deriveKey(password, salt);
    const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
    decipher.setAuthTag(tag);

    let decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');

    return decrypted;
  }

  /**
   * 保存 share
   */
  saveShare(share: Omit<ShareEntry, 'id' | 'createdAt' | 'encryptedShare'> & { rawShare: string }, password: string): ShareEntry {
    const encryptedShare = this.encrypt(share.rawShare, password);

    const entry: ShareEntry = {
      id: uuidv4(),
      sessionId: share.sessionId,
      walletName: share.walletName,
      partyId: share.partyId,
      partyIndex: share.partyIndex,
      threshold: share.threshold,
      publicKey: share.publicKey,
      encryptedShare,
      createdAt: new Date().toISOString(),
      metadata: share.metadata,
    };

    const shares = this.store.get('shares', []);
    shares.push(entry);
    this.store.set('shares', shares);

    return entry;
  }

  /**
   * 获取 share 列表 (不含加密数据)
   */
  listShares(): Omit<ShareEntry, 'encryptedShare'>[] {
    const shares = this.store.get('shares', []);
    return shares.map(({ encryptedShare: _, ...rest }) => rest);
  }

  /**
   * 获取单个 share (解密)
   */
  getShare(id: string, password: string): ShareEntry & { rawShare: string } {
    const shares = this.store.get('shares', []);
    const share = shares.find((s) => s.id === id);

    if (!share) {
      throw new Error('Share not found');
    }

    const rawShare = this.decrypt(share.encryptedShare, password);

    return {
      ...share,
      rawShare,
    };
  }

  /**
   * 更新 share 使用时间
   */
  updateLastUsed(id: string): void {
    const shares = this.store.get('shares', []);
    const index = shares.findIndex((s) => s.id === id);

    if (index !== -1) {
      shares[index].lastUsedAt = new Date().toISOString();
      this.store.set('shares', shares);
    }
  }

  /**
   * 删除 share
   */
  deleteShare(id: string): void {
    const shares = this.store.get('shares', []);
    const filtered = shares.filter((s) => s.id !== id);
    this.store.set('shares', filtered);
  }

  /**
   * 导出 share (加密后的备份文件)
   */
  exportShare(id: string, password: string): Buffer {
    const share = this.getShare(id, password);

    const exportData = {
      version: '1.0.0',
      exportedAt: new Date().toISOString(),
      share: {
        ...share,
        // 导出时使用新密码重新加密
        encryptedShare: this.encrypt(share.rawShare, password),
      },
    };

    // 再次加密整个导出数据
    const encryptedExport = this.encrypt(JSON.stringify(exportData), password);

    return Buffer.from(encryptedExport, 'utf8');
  }

  /**
   * 导入 share
   */
  importShare(data: Buffer, password: string): ShareEntry {
    const encryptedExport = data.toString('utf8');

    // 解密导出数据
    const decrypted = this.decrypt(encryptedExport, password);
    const exportData = JSON.parse(decrypted);

    if (!exportData.version || !exportData.share) {
      throw new Error('Invalid export file format');
    }

    // 解密 share 数据
    const rawShare = this.decrypt(exportData.share.encryptedShare, password);

    // 检查是否已存在相同的 share
    const shares = this.store.get('shares', []);
    const existing = shares.find(
      (s) => s.sessionId === exportData.share.sessionId && s.partyId === exportData.share.partyId
    );

    if (existing) {
      throw new Error('Share already exists');
    }

    // 保存导入的 share
    return this.saveShare(
      {
        sessionId: exportData.share.sessionId,
        walletName: exportData.share.walletName,
        partyId: exportData.share.partyId,
        partyIndex: exportData.share.partyIndex,
        threshold: exportData.share.threshold,
        publicKey: exportData.share.publicKey,
        metadata: exportData.share.metadata,
        rawShare,
      },
      password
    );
  }

  /**
   * 获取设置
   */
  getSettings() {
    return this.store.get('settings');
  }

  /**
   * 更新设置
   */
  updateSettings(settings: Partial<StoreSchema['settings']>): void {
    const current = this.store.get('settings');
    this.store.set('settings', { ...current, ...settings });
  }

  /**
   * 保存设置 (完全替换)
   */
  saveSettings(settings: StoreSchema['settings']): void {
    this.store.set('settings', settings);
  }
}
