import { db, id, now, visibleClause } from '../db.js';
import { applicationSchema } from '../forms/schemas.js';
import { evaluateUpdateState } from '../services/appVersionService.js';

function camelApplication(row) {
  if (!row) return null;
  const base = {
    id: row.id,
    name: row.name,
    vendor: row.vendor || '',
    publisher: row.publisher || '',
    currentVersion: row.current_version || '',
    latestKnownVersion: row.latest_known_version || '',
    versionSource: row.version_source || 'manual',
    versionSourceRef: row.version_source_ref || '',
    graphConnectionId: row.graph_connection_id || null,
    currentGraphAppId: row.current_graph_app_id || '',
    autoCheck: Boolean(row.auto_check),
    lastCheckedAt: row.last_checked_at || '',
    lastCheckMessage: row.last_check_message || '',
    notes: row.notes || '',
    visibility: row.visibility,
    ownerUserId: row.owner_user_id,
    groupId: row.group_id,
    groupName: row.group_name || null,
    deploymentCount: row.deployment_count ?? 0,
    createdAt: row.created_at,
    updatedAt: row.updated_at
  };
  // Surface the computed update state so callers don't re-derive it.
  base.updateState = evaluateUpdateState(base);
  return base;
}

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

export function listApplications(userId) {
  return db.prepare(`
    SELECT a.*, g.name AS group_name,
      (SELECT COUNT(*) FROM intune_deployments d WHERE d.application_id = a.id) AS deployment_count
    FROM applications a
    LEFT JOIN groups g ON g.id = a.group_id
    WHERE ${visibleClause('a')}
    ORDER BY a.name
  `).all(userId, userId).map(camelApplication);
}

export function loadApplication(applicationId, userId) {
  const row = db.prepare(`
    SELECT a.*, g.name AS group_name,
      (SELECT COUNT(*) FROM intune_deployments d WHERE d.application_id = a.id) AS deployment_count
    FROM applications a
    LEFT JOIN groups g ON g.id = a.group_id
    WHERE a.id = ? AND ${visibleClause('a')}
  `).get(applicationId, userId, userId);
  return camelApplication(row);
}

export function createApplication(body, userId) {
  const payload = applicationSchema.parse(body);
  const applicationId = id('app');
  db.prepare(`
    INSERT INTO applications (
      id, name, vendor, publisher, current_version, latest_known_version, version_source,
      version_source_ref, graph_connection_id, current_graph_app_id, auto_check, notes,
      visibility, owner_user_id, group_id, created_by, created_at, updated_at
    )
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `).run(
    applicationId,
    payload.name,
    payload.vendor,
    payload.publisher,
    payload.currentVersion,
    payload.latestKnownVersion,
    payload.versionSource,
    payload.versionSourceRef,
    payload.graphConnectionId || null,
    payload.currentGraphAppId,
    payload.autoCheck ? 1 : 0,
    payload.notes,
    payload.visibility,
    userId,
    scopedGroupId(payload),
    userId,
    now(),
    now()
  );
  return loadApplication(applicationId, userId);
}

export function updateApplication(applicationId, body, userId) {
  const existing = loadApplication(applicationId, userId);
  if (!existing) return null;
  const payload = applicationSchema.parse({ ...existing, ...body });
  db.prepare(`
    UPDATE applications
    SET name = ?, vendor = ?, publisher = ?, current_version = ?, latest_known_version = ?,
        version_source = ?, version_source_ref = ?, graph_connection_id = ?, current_graph_app_id = ?,
        auto_check = ?, notes = ?, visibility = ?, group_id = ?, updated_at = ?
    WHERE id = ?
  `).run(
    payload.name,
    payload.vendor,
    payload.publisher,
    payload.currentVersion,
    payload.latestKnownVersion,
    payload.versionSource,
    payload.versionSourceRef,
    payload.graphConnectionId || null,
    payload.currentGraphAppId,
    payload.autoCheck ? 1 : 0,
    payload.notes,
    payload.visibility,
    scopedGroupId(payload),
    now(),
    applicationId
  );
  return loadApplication(applicationId, userId);
}

export function deleteApplication(applicationId, userId) {
  db.prepare(`DELETE FROM applications WHERE id = ? AND ${visibleClause()}`).run(applicationId, userId, userId);
}

// Record the outcome of an upstream version check on the catalog entry.
export function recordVersionCheck(applicationId, userId, { latestKnownVersion, message }) {
  const existing = loadApplication(applicationId, userId);
  if (!existing) return null;
  applyVersionCheck(applicationId, { latestKnownVersion: latestKnownVersion ?? existing.latestKnownVersion, message });
  return loadApplication(applicationId, userId);
}

// System-level write used by the background worker (no visibility scope).
export function applyVersionCheck(applicationId, { latestKnownVersion, message }) {
  db.prepare(`
    UPDATE applications
    SET latest_known_version = COALESCE(?, latest_known_version), last_checked_at = ?, last_check_message = ?, updated_at = ?
    WHERE id = ?
  `).run(latestKnownVersion ?? null, now(), message || '', now(), applicationId);
}

// Applications opted into automatic upstream version checks. System context.
export function listAutoCheckApplications() {
  return db.prepare('SELECT * FROM applications WHERE auto_check = 1').all().map(camelApplication);
}
