/**
 * Registry Repository
 * Handles CRUD operations for registries and registry_tokens tables
 */

import { BaseRepository } from '../base.repository.ts';
import type { IRegistry, IRegistryToken } from '../../types.ts';

export class RegistryRepository extends BaseRepository {
  // ============ Registries ============

  async createRegistry(registry: Omit<IRegistry, 'id'>): Promise<IRegistry> {
    const now = Date.now();
    this.query(
      'INSERT INTO registries (url, username, password_encrypted, created_at) VALUES (?, ?, ?, ?)',
      [registry.url, registry.username, registry.passwordEncrypted, now]
    );

    return this.getRegistryByURL(registry.url)!;
  }

  getRegistryByURL(url: string): IRegistry | null {
    const rows = this.query('SELECT * FROM registries WHERE url = ?', [url]);
    return rows.length > 0 ? this.rowToRegistry(rows[0]) : null;
  }

  getAllRegistries(): IRegistry[] {
    const rows = this.query('SELECT * FROM registries ORDER BY created_at DESC');
    return rows.map((row) => this.rowToRegistry(row));
  }

  deleteRegistry(url: string): void {
    this.query('DELETE FROM registries WHERE url = ?', [url]);
  }

  private rowToRegistry(row: any): IRegistry {
    return {
      id: Number(row.id || row[0]),
      url: String(row.url || row[1]),
      username: String(row.username || row[2]),
      passwordEncrypted: String(row.password_encrypted || row[3]),
      createdAt: Number(row.created_at || row[4]),
    };
  }

  // ============ Registry Tokens ============

  createToken(token: Omit<IRegistryToken, 'id'>): IRegistryToken {
    const scopeJson = Array.isArray(token.scope) ? JSON.stringify(token.scope) : token.scope;

    this.query(
      `INSERT INTO registry_tokens (name, token_hash, token_type, scope, expires_at, created_at, last_used_at, created_by)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        token.name,
        token.tokenHash,
        token.type,
        scopeJson,
        token.expiresAt,
        token.createdAt,
        token.lastUsedAt,
        token.createdBy,
      ]
    );

    const rows = this.query('SELECT * FROM registry_tokens WHERE id = last_insert_rowid()');
    return this.rowToToken(rows[0]);
  }

  getTokenById(id: number): IRegistryToken | null {
    const rows = this.query('SELECT * FROM registry_tokens WHERE id = ?', [id]);
    return rows.length > 0 ? this.rowToToken(rows[0]) : null;
  }

  getTokenByHash(tokenHash: string): IRegistryToken | null {
    const rows = this.query('SELECT * FROM registry_tokens WHERE token_hash = ?', [tokenHash]);
    return rows.length > 0 ? this.rowToToken(rows[0]) : null;
  }

  getAllTokens(): IRegistryToken[] {
    const rows = this.query('SELECT * FROM registry_tokens ORDER BY created_at DESC');
    return rows.map((row) => this.rowToToken(row));
  }

  getTokensByType(type: 'global' | 'ci'): IRegistryToken[] {
    const rows = this.query('SELECT * FROM registry_tokens WHERE token_type = ? ORDER BY created_at DESC', [type]);
    return rows.map((row) => this.rowToToken(row));
  }

  updateTokenLastUsed(id: number): void {
    this.query('UPDATE registry_tokens SET last_used_at = ? WHERE id = ?', [Date.now(), id]);
  }

  deleteToken(id: number): void {
    this.query('DELETE FROM registry_tokens WHERE id = ?', [id]);
  }

  private rowToToken(row: any): IRegistryToken {
    let scope: 'all' | string[];
    const scopeRaw = row.scope || row[4];
    if (scopeRaw === 'all') {
      scope = 'all';
    } else {
      try {
        scope = JSON.parse(String(scopeRaw));
      } catch {
        scope = 'all';
      }
    }

    return {
      id: Number(row.id || row[0]),
      name: String(row.name || row[1]),
      tokenHash: String(row.token_hash || row[2]),
      type: String(row.token_type || row[3]) as IRegistryToken['type'],
      scope,
      expiresAt: row.expires_at || row[5] ? Number(row.expires_at || row[5]) : null,
      createdAt: Number(row.created_at || row[6]),
      lastUsedAt: row.last_used_at || row[7] ? Number(row.last_used_at || row[7]) : null,
      createdBy: String(row.created_by || row[8]),
    };
  }
}
