import { db, id, json, now, parseJson, visibleClause } from '../db.js';
import { camelHost } from './mappers.js';

export function listHosts(userId) {
  return db.prepare(`
    SELECT h.*, c.name AS credential_name, g.name AS group_name
    FROM hosts h
    LEFT JOIN credentials c ON c.id = h.credential_id
    LEFT JOIN groups g ON g.id = h.group_id
    WHERE ${visibleClause('h')}
    ORDER BY h.name
  `).all(userId, userId).map(camelHost);
}

function scopedGroupId(payload) {
  return payload.visibility === 'group' ? payload.groupId || null : null;
}

export function createHost(payload, userId) {
  const hostId = id('hst');
  db.prepare(`
    INSERT INTO hosts (id, name, fqdn, address, os_family, transport, port, credential_id, tags, notes,
                       visibility, owner_user_id, group_id, created_at, updated_at)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `).run(
    hostId,
    payload.name,
    payload.fqdn || '',
    payload.address,
    payload.osFamily,
    payload.transport,
    payload.port || null,
    payload.credentialId || null,
    json(payload.tags),
    payload.notes || '',
    payload.visibility || 'shared',
    userId,
    scopedGroupId(payload),
    now(),
    now()
  );
  return camelHost(db.prepare('SELECT * FROM hosts WHERE id = ?').get(hostId));
}

export function findVisibleHostByIdentity(payload, userId) {
  const values = [payload.name, payload.address, payload.fqdn]
    .map((value) => String(value || '').trim().toLowerCase())
    .filter(Boolean);
  if (!values.length) return null;
  const placeholders = values.map(() => '?').join(', ');
  const row = db.prepare(`
    SELECT *
    FROM hosts
    WHERE ${visibleClause()}
      AND (
        lower(name) IN (${placeholders})
        OR lower(address) IN (${placeholders})
        OR lower(coalesce(fqdn, '')) IN (${placeholders})
      )
    LIMIT 1
  `).get(userId, userId, ...values, ...values, ...values);
  return row ? camelHost(row) : null;
}

export function updateHost(hostId, payload, userId) {
  const existing = db.prepare(`SELECT * FROM hosts WHERE id = ? AND ${visibleClause()}`).get(hostId, userId, userId);
  if (!existing) return null;
  const visibility = payload.visibility || existing.visibility;
  db.prepare(`
    UPDATE hosts
    SET name = ?, fqdn = ?, address = ?, os_family = ?, transport = ?, port = ?, credential_id = ?,
        tags = ?, notes = ?, visibility = ?, group_id = ?, updated_at = ?
    WHERE id = ?
  `).run(
    payload.name || existing.name,
    payload.fqdn ?? existing.fqdn,
    payload.address || existing.address,
    payload.osFamily || existing.os_family,
    payload.transport || existing.transport,
    payload.port ?? existing.port,
    payload.credentialId ?? existing.credential_id,
    json(payload.tags ?? parseJson(existing.tags)),
    payload.notes ?? existing.notes,
    visibility,
    visibility === 'group' ? (payload.groupId ?? existing.group_id) : null,
    now(),
    hostId
  );
  return camelHost(db.prepare('SELECT * FROM hosts WHERE id = ?').get(hostId));
}

export function deleteHost(hostId, userId) {
  db.prepare(`DELETE FROM hosts WHERE id = ? AND ${visibleClause()}`).run(hostId, userId, userId);
}

// Return only the host IDs from the requested set that are visible to the user.
// Used to stop a RunPlan from targeting hosts the operator cannot see.
export function filterVisibleHostIds(hostIds = [], userId) {
  if (!hostIds.length) return [];
  const visible = new Set(
    db.prepare(`SELECT id FROM hosts WHERE ${visibleClause()}`).all(userId, userId).map((row) => row.id)
  );
  return hostIds.filter((hostId) => visible.has(hostId));
}
