/**
 * Service Repository
 * Handles CRUD operations for services table
 */

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

export class ServiceRepository extends BaseRepository {
  async create(service: Omit<IService, 'id'>): Promise<IService> {
    const now = Date.now();
    this.query(
      `INSERT INTO services (
        name, image, registry, env_vars, volumes, published_ports, port, domain, container_id, status,
        created_at, updated_at,
        use_onebox_registry, registry_repository, registry_image_tag,
        auto_update_on_push, image_digest, platform_requirements,
        app_template_id, app_template_version
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        service.name,
        service.image,
        service.registry || null,
        JSON.stringify(service.envVars),
        JSON.stringify(service.volumes || []),
        JSON.stringify(service.publishedPorts || []),
        service.port,
        service.domain || null,
        service.containerID || null,
        service.status,
        now,
        now,
        service.useOneboxRegistry ? 1 : 0,
        service.registryRepository || null,
        service.registryImageTag || 'latest',
        service.autoUpdateOnPush ? 1 : 0,
        service.imageDigest || null,
        JSON.stringify(service.platformRequirements || {}),
        service.appTemplateId || null,
        service.appTemplateVersion || null,
      ]
    );

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

  getByName(name: string): IService | null {
    const rows = this.query('SELECT * FROM services WHERE name = ?', [name]);
    if (rows.length > 0) {
      logger.info(`getServiceByName: raw row data: ${JSON.stringify(rows[0])}`);
      const service = this.rowToService(rows[0]);
      logger.info(`getServiceByName: service object containerID: ${service.containerID}`);
      return service;
    }
    return null;
  }

  getById(id: number): IService | null {
    const rows = this.query('SELECT * FROM services WHERE id = ?', [id]);
    return rows.length > 0 ? this.rowToService(rows[0]) : null;
  }

  getAll(): IService[] {
    const rows = this.query('SELECT * FROM services ORDER BY created_at DESC');
    return rows.map((row) => this.rowToService(row));
  }

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

    if (updates.image !== undefined) {
      fields.push('image = ?');
      values.push(updates.image);
    }
    if (updates.registry !== undefined) {
      fields.push('registry = ?');
      values.push(updates.registry);
    }
    if (updates.envVars !== undefined) {
      fields.push('env_vars = ?');
      values.push(JSON.stringify(updates.envVars));
    }
    if (updates.volumes !== undefined) {
      fields.push('volumes = ?');
      values.push(JSON.stringify(updates.volumes));
    }
    if (updates.publishedPorts !== undefined) {
      fields.push('published_ports = ?');
      values.push(JSON.stringify(updates.publishedPorts));
    }
    if (updates.port !== undefined) {
      fields.push('port = ?');
      values.push(updates.port);
    }
    if (updates.domain !== undefined) {
      fields.push('domain = ?');
      values.push(updates.domain);
    }
    if (updates.containerID !== undefined) {
      fields.push('container_id = ?');
      values.push(updates.containerID);
    }
    if (updates.status !== undefined) {
      fields.push('status = ?');
      values.push(updates.status);
    }
    if (updates.useOneboxRegistry !== undefined) {
      fields.push('use_onebox_registry = ?');
      values.push(updates.useOneboxRegistry ? 1 : 0);
    }
    if (updates.registryRepository !== undefined) {
      fields.push('registry_repository = ?');
      values.push(updates.registryRepository);
    }
    if (updates.registryImageTag !== undefined) {
      fields.push('registry_image_tag = ?');
      values.push(updates.registryImageTag);
    }
    if (updates.autoUpdateOnPush !== undefined) {
      fields.push('auto_update_on_push = ?');
      values.push(updates.autoUpdateOnPush ? 1 : 0);
    }
    if (updates.imageDigest !== undefined) {
      fields.push('image_digest = ?');
      values.push(updates.imageDigest);
    }
    if (updates.platformRequirements !== undefined) {
      fields.push('platform_requirements = ?');
      values.push(JSON.stringify(updates.platformRequirements));
    }
    if (updates.includeImageInBackup !== undefined) {
      fields.push('include_image_in_backup = ?');
      values.push(updates.includeImageInBackup ? 1 : 0);
    }
    if (updates.appTemplateId !== undefined) {
      fields.push('app_template_id = ?');
      values.push(updates.appTemplateId);
    }
    if (updates.appTemplateVersion !== undefined) {
      fields.push('app_template_version = ?');
      values.push(updates.appTemplateVersion);
    }

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

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

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

  private rowToService(row: any): IService {
    let envVars = {};
    const envVarsRaw = row.env_vars || row[4];
    if (envVarsRaw && envVarsRaw !== 'undefined' && envVarsRaw !== 'null') {
      try {
        envVars = JSON.parse(String(envVarsRaw));
      } catch (e) {
        logger.warn(`Failed to parse env_vars for service: ${getErrorMessage(e)}`);
        envVars = {};
      }
    }

    let platformRequirements: IPlatformRequirements | undefined;
    const platformReqRaw = row.platform_requirements;
    if (platformReqRaw && platformReqRaw !== 'undefined' && platformReqRaw !== 'null' && platformReqRaw !== '{}') {
      try {
        platformRequirements = JSON.parse(String(platformReqRaw));
      } catch (e) {
        logger.warn(`Failed to parse platform_requirements for service: ${getErrorMessage(e)}`);
        platformRequirements = undefined;
      }
    }

    let volumes = [];
    const volumesRaw = row.volumes ?? row[20];
    if (volumesRaw && volumesRaw !== 'undefined' && volumesRaw !== 'null') {
      try {
        volumes = JSON.parse(String(volumesRaw));
      } catch (e) {
        logger.warn(`Failed to parse volumes for service: ${getErrorMessage(e)}`);
        volumes = [];
      }
    }

    let publishedPorts = [];
    const publishedPortsRaw = row.published_ports;
    if (publishedPortsRaw && publishedPortsRaw !== 'undefined' && publishedPortsRaw !== 'null') {
      try {
        publishedPorts = JSON.parse(String(publishedPortsRaw));
      } catch (e) {
        logger.warn(`Failed to parse published_ports for service: ${getErrorMessage(e)}`);
        publishedPorts = [];
      }
    }

    return {
      id: Number(row.id || row[0]),
      name: String(row.name || row[1]),
      image: String(row.image || row[2]),
      registry: (row.registry || row[3]) ? String(row.registry || row[3]) : undefined,
      envVars,
      volumes,
      publishedPorts,
      port: Number(row.port ?? row[6] ?? row[5]),
      domain: (row.domain ?? row[7] ?? row[6]) ? String(row.domain ?? row[7] ?? row[6]) : undefined,
      containerID: (row.container_id ?? row[8] ?? row[7]) ? String(row.container_id ?? row[8] ?? row[7]) : undefined,
      status: String(row.status ?? row[9] ?? row[8]) as IService['status'],
      createdAt: Number(row.created_at ?? row[10] ?? row[9]),
      updatedAt: Number(row.updated_at ?? row[11] ?? row[10]),
      useOneboxRegistry: row.use_onebox_registry ? Boolean(row.use_onebox_registry) : undefined,
      registryRepository: row.registry_repository ? String(row.registry_repository) : undefined,
      registryImageTag: row.registry_image_tag ? String(row.registry_image_tag) : undefined,
      autoUpdateOnPush: row.auto_update_on_push ? Boolean(row.auto_update_on_push) : undefined,
      imageDigest: row.image_digest ? String(row.image_digest) : undefined,
      platformRequirements,
      includeImageInBackup: row.include_image_in_backup !== undefined
        ? Boolean(row.include_image_in_backup)
        : true, // Default to true
      appTemplateId: row.app_template_id ? String(row.app_template_id) : undefined,
      appTemplateVersion: row.app_template_version ? String(row.app_template_version) : undefined,
    };
  }
}
