// =============================================================================
// Pure Coolify API — no ToolContext coupling, no registry coupling.
//
// Everything in here takes a plain { apiUrl, apiToken } config and calls
// the Coolify v1 API directly. Security guardrails (PROTECTED_COOLIFY_PROJECT,
// PROTECTED_COOLIFY_APPS, assertCoolifyDeployable) are enforced inside each
// function so every caller — in-process tool handler, MCP server, or future
// direct SDK user — gets the same protection.
//
// This is the shared core consumed by:
//   - tools/coolify.ts  (in-process registry used by agent-runner loop)
//   - mcp/coolify-server.ts  (stdio MCP server exposed to Goose/Claude/Cursor)
// =============================================================================

import { PROTECTED_COOLIFY_PROJECT, PROTECTED_COOLIFY_APPS, assertCoolifyDeployable } from './security';

export interface CoolifyConfig {
    apiUrl: string;
    apiToken: string;
}

type CoolifyError = { error: string };

async function coolifyFetch(
    cfg: CoolifyConfig,
    path: string,
    method: string = 'GET',
    body?: unknown
): Promise<unknown> {
    const res = await fetch(`${cfg.apiUrl}/api/v1${path}`, {
        method,
        headers: {
            'Authorization': `Bearer ${cfg.apiToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        },
        body: body ? JSON.stringify(body) : undefined
    });
    if (!res.ok) {
        return { error: `Coolify API error: ${res.status} ${res.statusText}` } satisfies CoolifyError;
    }
    return res.json();
}

// ---------------------------------------------------------------------------
// Public API — each function corresponds 1:1 with a registered tool today
// ---------------------------------------------------------------------------

export async function listProjects(cfg: CoolifyConfig): Promise<unknown> {
    const projects = await coolifyFetch(cfg, '/projects') as any[];
    if (!Array.isArray(projects)) return projects;
    return projects.filter((p: any) => p.uuid !== PROTECTED_COOLIFY_PROJECT);
}

export async function listApplications(cfg: CoolifyConfig, projectUuid: string): Promise<unknown> {
    const all = await coolifyFetch(cfg, '/applications') as any[];
    if (!Array.isArray(all)) return all;
    return all.filter((a: any) => a.project_uuid === projectUuid);
}

export async function deploy(cfg: CoolifyConfig, applicationUuid: string): Promise<unknown> {
    assertCoolifyDeployable(applicationUuid);
    const apps = await coolifyFetch(cfg, '/applications') as any[];
    if (Array.isArray(apps)) {
        const app = apps.find((a: any) => a.uuid === applicationUuid);
        if (app?.project_uuid === PROTECTED_COOLIFY_PROJECT) {
            return {
                error: `SECURITY: App "${applicationUuid}" belongs to the protected Vibn project. Agents cannot deploy platform apps.`
            } satisfies CoolifyError;
        }
    }
    return coolifyFetch(cfg, `/applications/${applicationUuid}/deploy`, 'POST');
}

export async function getLogs(cfg: CoolifyConfig, applicationUuid: string, limit: number = 50): Promise<unknown> {
    return coolifyFetch(cfg, `/applications/${applicationUuid}/logs?limit=${limit}`);
}

export async function listAllApps(cfg: CoolifyConfig): Promise<unknown> {
    const apps = await coolifyFetch(cfg, '/applications') as any[];
    if (!Array.isArray(apps)) return apps;
    return apps
        .filter((a: any) => a.project_uuid !== PROTECTED_COOLIFY_PROJECT && !PROTECTED_COOLIFY_APPS.has(a.uuid))
        .map((a: any) => ({
            uuid: a.uuid,
            name: a.name,
            fqdn: a.fqdn,
            status: a.status,
            repo: a.git_repository,
            branch: a.git_branch
        }));
}

export async function getAppStatus(cfg: CoolifyConfig, appName: string): Promise<unknown> {
    const apps = await coolifyFetch(cfg, '/applications') as any[];
    if (!Array.isArray(apps)) return apps;
    const app = apps.find((a: any) =>
        a.name?.toLowerCase() === appName.toLowerCase() || a.uuid === appName
    );
    if (!app) return { error: `App "${appName}" not found` } satisfies CoolifyError;
    if (PROTECTED_COOLIFY_APPS.has(app.uuid) || app.project_uuid === PROTECTED_COOLIFY_PROJECT) {
        return {
            error: `SECURITY: "${appName}" is a protected Vibn platform app. Status is not exposed to agents.`
        } satisfies CoolifyError;
    }
    const logs = await coolifyFetch(cfg, `/applications/${app.uuid}/logs?limit=20`);
    return { name: app.name, uuid: app.uuid, status: app.status, fqdn: app.fqdn, logs };
}

export async function deployApp(cfg: CoolifyConfig, appName: string): Promise<unknown> {
    const apps = await coolifyFetch(cfg, '/applications') as any[];
    if (!Array.isArray(apps)) return apps;
    const app = apps.find((a: any) =>
        a.name?.toLowerCase() === appName.toLowerCase() || a.uuid === appName
    );
    if (!app) return { error: `App "${appName}" not found` } satisfies CoolifyError;
    if (PROTECTED_COOLIFY_APPS.has(app.uuid) || app.project_uuid === PROTECTED_COOLIFY_PROJECT) {
        return {
            error: `SECURITY: "${appName}" is a protected Vibn platform application. ` +
                   `Agents can only deploy user project apps, not platform infrastructure.`
        } satisfies CoolifyError;
    }
    // Non-project-prefixed deploy endpoint — older Coolify entry point still in use
    const result = await fetch(`${cfg.apiUrl}/api/v1/deploy?uuid=${app.uuid}&force=false`, {
        headers: { 'Authorization': `Bearer ${cfg.apiToken}` }
    });
    return result.json();
}
