/**
 * Platform Repository
 * Handles CRUD operations for platform_services and platform_resources tables
 */

import { BaseRepository } from '../base.repository.ts';
import type { TBindValue } from '../types.ts';
import type { IPlatformService, IPlatformResource, TPlatformServiceType } from '../../types.ts';
import { logger } from '../../logging.ts';
import { getErrorMessage } from '../../utils/error.ts';

export class PlatformRepository extends BaseRepository {
  // ============ Platform Services ============

  createPlatformService(service: Omit<IPlatformService, 'id'>): IPlatformService {
    const now = Date.now();
    this.query(
      `INSERT INTO platform_services (name, type, status, container_id, config, admin_credentials_encrypted, created_at, updated_at)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        service.name,
        service.type,
        service.status,
        service.containerId || null,
        JSON.stringify(service.config),
        service.adminCredentialsEncrypted || null,
        now,
        now,
      ]
    );

    return this.getPlatformServiceByName(service.name)!;
  }

  getPlatformServiceByName(name: string): IPlatformService | null {
    const rows = this.query('SELECT * FROM platform_services WHERE name = ?', [name]);
    return rows.length > 0 ? this.rowToPlatformService(rows[0]) : null;
  }

  getPlatformServiceById(id: number): IPlatformService | null {
    const rows = this.query('SELECT * FROM platform_services WHERE id = ?', [id]);
    return rows.length > 0 ? this.rowToPlatformService(rows[0]) : null;
  }

  getPlatformServiceByType(type: TPlatformServiceType): IPlatformService | null {
    const rows = this.query('SELECT * FROM platform_services WHERE type = ?', [type]);
    return rows.length > 0 ? this.rowToPlatformService(rows[0]) : null;
  }

  getAllPlatformServices(): IPlatformService[] {
    const rows = this.query('SELECT * FROM platform_services ORDER BY created_at DESC');
    return rows.map((row) => this.rowToPlatformService(row));
  }

  updatePlatformService(id: number, updates: Partial<IPlatformService>): void {
    const fields: string[] = [];
    const values: TBindValue[] = [];

    if (updates.status !== undefined) {
      fields.push('status = ?');
      values.push(updates.status);
    }
    if (updates.containerId !== undefined) {
      fields.push('container_id = ?');
      values.push(updates.containerId);
    }
    if (updates.config !== undefined) {
      fields.push('config = ?');
      values.push(JSON.stringify(updates.config));
    }
    if (updates.adminCredentialsEncrypted !== undefined) {
      fields.push('admin_credentials_encrypted = ?');
      values.push(updates.adminCredentialsEncrypted);
    }

    fields.push('updated_at = ?');
    values.push(Date.now());
    values.push(id);

    this.query(`UPDATE platform_services SET ${fields.join(', ')} WHERE id = ?`, values);
  }

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

  private rowToPlatformService(row: any): IPlatformService {
    let config = { image: '', port: 0 };
    const configRaw = row.config;
    if (configRaw) {
      try {
        config = JSON.parse(String(configRaw));
      } catch (e) {
        logger.warn(`Failed to parse platform service config: ${getErrorMessage(e)}`);
      }
    }

    return {
      id: Number(row.id),
      name: String(row.name),
      type: String(row.type) as TPlatformServiceType,
      status: String(row.status) as IPlatformService['status'],
      containerId: row.container_id ? String(row.container_id) : undefined,
      config,
      adminCredentialsEncrypted: row.admin_credentials_encrypted ? String(row.admin_credentials_encrypted) : undefined,
      createdAt: Number(row.created_at),
      updatedAt: Number(row.updated_at),
    };
  }

  // ============ Platform Resources ============

  createPlatformResource(resource: Omit<IPlatformResource, 'id'>): IPlatformResource {
    const now = Date.now();
    this.query(
      `INSERT INTO platform_resources (platform_service_id, service_id, resource_type, resource_name, credentials_encrypted, created_at)
       VALUES (?, ?, ?, ?, ?, ?)`,
      [
        resource.platformServiceId,
        resource.serviceId,
        resource.resourceType,
        resource.resourceName,
        resource.credentialsEncrypted,
        now,
      ]
    );

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

  getPlatformResourceById(id: number): IPlatformResource | null {
    const rows = this.query('SELECT * FROM platform_resources WHERE id = ?', [id]);
    return rows.length > 0 ? this.rowToPlatformResource(rows[0]) : null;
  }

  getPlatformResourcesByService(serviceId: number): IPlatformResource[] {
    const rows = this.query('SELECT * FROM platform_resources WHERE service_id = ?', [serviceId]);
    return rows.map((row) => this.rowToPlatformResource(row));
  }

  getPlatformResourcesByPlatformService(platformServiceId: number): IPlatformResource[] {
    const rows = this.query('SELECT * FROM platform_resources WHERE platform_service_id = ?', [platformServiceId]);
    return rows.map((row) => this.rowToPlatformResource(row));
  }

  getAllPlatformResources(): IPlatformResource[] {
    const rows = this.query('SELECT * FROM platform_resources ORDER BY created_at DESC');
    return rows.map((row) => this.rowToPlatformResource(row));
  }

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

  deletePlatformResourcesByService(serviceId: number): void {
    this.query('DELETE FROM platform_resources WHERE service_id = ?', [serviceId]);
  }

  private rowToPlatformResource(row: any): IPlatformResource {
    return {
      id: Number(row.id),
      platformServiceId: Number(row.platform_service_id),
      serviceId: Number(row.service_id),
      resourceType: String(row.resource_type) as IPlatformResource['resourceType'],
      resourceName: String(row.resource_name),
      credentialsEncrypted: String(row.credentials_encrypted),
      createdAt: Number(row.created_at),
    };
  }
}
