import { Router } from "express";
import { catalogSkillListQuerySchema, companySkillCreateSchema, companySkillFileUpdateSchema, companySkillImportSchema, companySkillInstallCatalogSchema, companySkillInstallUpdateSchema, companySkillProjectScanRequestSchema, companySkillResetSchema, } from "@paperclipai/shared";
import { trackSkillImported } from "@paperclipai/shared/telemetry";
import { validate } from "../middleware/validate.js";
import { accessService, agentService, companySkillService, logActivity } from "../services/index.js";
import { getCatalogSkillOrThrow, listCatalogSkills, readCatalogSkillFile } from "../services/skills-catalog.js";
import { forbidden } from "../errors.js";
import { assertAuthenticated, assertCompanyAccess, getActorInfo } from "./authz.js";
import { getTelemetryClient } from "../telemetry.js";
export function companySkillRoutes(db) {
    const router = Router();
    const agents = agentService(db);
    const access = accessService(db);
    const svc = companySkillService(db);
    function canCreateAgents(agent) {
        if (!agent.permissions || typeof agent.permissions !== "object")
            return false;
        return Boolean(agent.permissions.canCreateAgents);
    }
    function asString(value) {
        if (typeof value !== "string")
            return null;
        const trimmed = value.trim();
        return trimmed.length > 0 ? trimmed : null;
    }
    function deriveTrackedSkillRef(skill) {
        if (skill.sourceType === "skills_sh") {
            return skill.key;
        }
        if (skill.sourceType !== "github") {
            return null;
        }
        const hostname = asString(skill.metadata?.hostname);
        if (hostname !== "github.com") {
            return null;
        }
        return skill.key;
    }
    function firstQueryString(value) {
        if (typeof value === "string")
            return value;
        if (Array.isArray(value) && typeof value[0] === "string")
            return value[0];
        return undefined;
    }
    async function assertCanMutateCompanySkills(req, companyId) {
        assertCompanyAccess(req, companyId);
        if (req.actor.type === "board") {
            if (req.actor.source === "local_implicit" || req.actor.isInstanceAdmin)
                return;
            const allowed = await access.canUser(companyId, req.actor.userId, "agents:create");
            if (!allowed) {
                throw forbidden("Missing permission: agents:create");
            }
            return;
        }
        if (!req.actor.agentId) {
            throw forbidden("Agent authentication required");
        }
        const actorAgent = await agents.getById(req.actor.agentId);
        if (!actorAgent || actorAgent.companyId !== companyId) {
            throw forbidden("Agent key cannot access another company");
        }
        const allowedByGrant = await access.hasPermission(companyId, "agent", actorAgent.id, "agents:create");
        if (allowedByGrant || canCreateAgents(actorAgent)) {
            return;
        }
        throw forbidden("Missing permission: can create agents");
    }
    router.get("/skills/catalog", async (req, res) => {
        assertAuthenticated(req);
        const query = catalogSkillListQuerySchema.parse({
            kind: firstQueryString(req.query.kind),
            category: firstQueryString(req.query.category),
            q: firstQueryString(req.query.q),
        });
        res.json(listCatalogSkills(query));
    });
    router.get("/skills/catalog/:catalogId/files", async (req, res) => {
        assertAuthenticated(req);
        const catalogRef = firstQueryString(req.query.ref) ?? req.params.catalogId;
        const relativePath = firstQueryString(req.query.path) ?? "SKILL.md";
        res.json(await readCatalogSkillFile(catalogRef, relativePath));
    });
    router.get("/skills/catalog/:catalogId", async (req, res) => {
        assertAuthenticated(req);
        const catalogRef = firstQueryString(req.query.ref) ?? req.params.catalogId;
        res.json(getCatalogSkillOrThrow(catalogRef));
    });
    router.get("/companies/:companyId/skills", async (req, res) => {
        const companyId = req.params.companyId;
        assertCompanyAccess(req, companyId);
        const result = await svc.list(companyId);
        res.json(result);
    });
    router.get("/companies/:companyId/skills/:skillId", async (req, res) => {
        const companyId = req.params.companyId;
        const skillId = req.params.skillId;
        assertCompanyAccess(req, companyId);
        const result = await svc.detail(companyId, skillId);
        if (!result) {
            res.status(404).json({ error: "Skill not found" });
            return;
        }
        res.json(result);
    });
    router.get("/companies/:companyId/skills/:skillId/update-status", async (req, res) => {
        const companyId = req.params.companyId;
        const skillId = req.params.skillId;
        assertCompanyAccess(req, companyId);
        const result = await svc.updateStatus(companyId, skillId);
        if (!result) {
            res.status(404).json({ error: "Skill not found" });
            return;
        }
        res.json(result);
    });
    router.get("/companies/:companyId/skills/:skillId/files", async (req, res) => {
        const companyId = req.params.companyId;
        const skillId = req.params.skillId;
        const relativePath = String(req.query.path ?? "SKILL.md");
        assertCompanyAccess(req, companyId);
        const result = await svc.readFile(companyId, skillId, relativePath);
        if (!result) {
            res.status(404).json({ error: "Skill not found" });
            return;
        }
        res.json(result);
    });
    router.post("/companies/:companyId/skills", validate(companySkillCreateSchema), async (req, res) => {
        const companyId = req.params.companyId;
        await assertCanMutateCompanySkills(req, companyId);
        const result = await svc.createLocalSkill(companyId, req.body);
        const actor = getActorInfo(req);
        await logActivity(db, {
            companyId,
            actorType: actor.actorType,
            actorId: actor.actorId,
            agentId: actor.agentId,
            runId: actor.runId,
            action: "company.skill_created",
            entityType: "company_skill",
            entityId: result.id,
            details: {
                slug: result.slug,
                name: result.name,
            },
        });
        res.status(201).json(result);
    });
    router.patch("/companies/:companyId/skills/:skillId/files", validate(companySkillFileUpdateSchema), async (req, res) => {
        const companyId = req.params.companyId;
        const skillId = req.params.skillId;
        await assertCanMutateCompanySkills(req, companyId);
        const result = await svc.updateFile(companyId, skillId, String(req.body.path ?? ""), String(req.body.content ?? ""));
        const actor = getActorInfo(req);
        await logActivity(db, {
            companyId,
            actorType: actor.actorType,
            actorId: actor.actorId,
            agentId: actor.agentId,
            runId: actor.runId,
            action: "company.skill_file_updated",
            entityType: "company_skill",
            entityId: skillId,
            details: {
                path: result.path,
                markdown: result.markdown,
            },
        });
        res.json(result);
    });
    router.post("/companies/:companyId/skills/import", validate(companySkillImportSchema), async (req, res) => {
        const companyId = req.params.companyId;
        await assertCanMutateCompanySkills(req, companyId);
        const source = String(req.body.source ?? "");
        const result = await svc.importFromSource(companyId, source);
        const actor = getActorInfo(req);
        await logActivity(db, {
            companyId,
            actorType: actor.actorType,
            actorId: actor.actorId,
            agentId: actor.agentId,
            runId: actor.runId,
            action: "company.skills_imported",
            entityType: "company",
            entityId: companyId,
            details: {
                source,
                importedCount: result.imported.length,
                importedSlugs: result.imported.map((skill) => skill.slug),
                warningCount: result.warnings.length,
            },
        });
        const telemetryClient = getTelemetryClient();
        if (telemetryClient) {
            for (const skill of result.imported) {
                trackSkillImported(telemetryClient, {
                    sourceType: skill.sourceType,
                    skillRef: deriveTrackedSkillRef(skill),
                });
            }
        }
        res.status(201).json(result);
    });
    router.post("/companies/:companyId/skills/install-catalog", validate(companySkillInstallCatalogSchema), async (req, res) => {
        const companyId = req.params.companyId;
        await assertCanMutateCompanySkills(req, companyId);
        const result = await svc.installFromCatalog(companyId, req.body);
        const actor = getActorInfo(req);
        await logActivity(db, {
            companyId,
            actorType: actor.actorType,
            actorId: actor.actorId,
            agentId: actor.agentId,
            runId: actor.runId,
            action: result.action === "created" ? "company.skill_catalog_installed" : "company.skill_catalog_updated",
            entityType: "company_skill",
            entityId: result.skill.id,
            details: {
                action: result.action,
                catalogId: result.catalogSkill.id,
                catalogKey: result.catalogSkill.key,
                slug: result.skill.slug,
                originHash: result.catalogSkill.contentHash,
                warningCount: result.warnings.length,
            },
        });
        res.status(result.action === "created" ? 201 : 200).json(result);
    });
    router.post("/companies/:companyId/skills/scan-projects", validate(companySkillProjectScanRequestSchema), async (req, res) => {
        const companyId = req.params.companyId;
        await assertCanMutateCompanySkills(req, companyId);
        const result = await svc.scanProjectWorkspaces(companyId, req.body);
        const actor = getActorInfo(req);
        await logActivity(db, {
            companyId,
            actorType: actor.actorType,
            actorId: actor.actorId,
            agentId: actor.agentId,
            runId: actor.runId,
            action: "company.skills_scanned",
            entityType: "company",
            entityId: companyId,
            details: {
                scannedProjects: result.scannedProjects,
                scannedWorkspaces: result.scannedWorkspaces,
                discovered: result.discovered,
                importedCount: result.imported.length,
                updatedCount: result.updated.length,
                conflictCount: result.conflicts.length,
                warningCount: result.warnings.length,
            },
        });
        res.json(result);
    });
    router.delete("/companies/:companyId/skills/:skillId", async (req, res) => {
        const companyId = req.params.companyId;
        const skillId = req.params.skillId;
        await assertCanMutateCompanySkills(req, companyId);
        const result = await svc.deleteSkill(companyId, skillId);
        if (!result) {
            res.status(404).json({ error: "Skill not found" });
            return;
        }
        const actor = getActorInfo(req);
        await logActivity(db, {
            companyId,
            actorType: actor.actorType,
            actorId: actor.actorId,
            agentId: actor.agentId,
            runId: actor.runId,
            action: "company.skill_deleted",
            entityType: "company_skill",
            entityId: result.id,
            details: {
                slug: result.slug,
                name: result.name,
            },
        });
        res.json(result);
    });
    router.post("/companies/:companyId/skills/:skillId/audit", async (req, res) => {
        const companyId = req.params.companyId;
        const skillId = req.params.skillId;
        await assertCanMutateCompanySkills(req, companyId);
        const result = await svc.auditSkill(companyId, skillId);
        if (!result) {
            res.status(404).json({ error: "Skill not found" });
            return;
        }
        const actor = getActorInfo(req);
        await logActivity(db, {
            companyId,
            actorType: actor.actorType,
            actorId: actor.actorId,
            agentId: actor.agentId,
            runId: actor.runId,
            action: "company.skill_audited",
            entityType: "company_skill",
            entityId: skillId,
            details: {
                verdict: result.verdict,
                codes: result.codes,
                installedHash: result.installedHash,
                originHash: result.originHash,
                scanVersion: result.scanVersion,
            },
        });
        res.json(result);
    });
    router.post("/companies/:companyId/skills/:skillId/install-update", validate(companySkillInstallUpdateSchema), async (req, res) => {
        const companyId = req.params.companyId;
        const skillId = req.params.skillId;
        await assertCanMutateCompanySkills(req, companyId);
        const before = await svc.getById(companyId, skillId);
        const result = await svc.installUpdate(companyId, skillId, req.body);
        if (!result) {
            res.status(404).json({ error: "Skill not found" });
            return;
        }
        const actor = getActorInfo(req);
        await logActivity(db, {
            companyId,
            actorType: actor.actorType,
            actorId: actor.actorId,
            agentId: actor.agentId,
            runId: actor.runId,
            action: "company.skill_update_installed",
            entityType: "company_skill",
            entityId: result.id,
            details: {
                slug: result.slug,
                previousOriginHash: before?.metadata?.originHash ?? before?.sourceRef ?? null,
                previousOriginVersion: before?.metadata?.originVersion ?? null,
                newOriginHash: result.metadata?.originHash ?? result.sourceRef,
                newOriginVersion: result.metadata?.originVersion ?? null,
                driftDetected: Boolean(before?.metadata?.userModifiedAt),
                force: Boolean(req.body.force),
                auditVerdict: result.metadata?.auditVerdict ?? null,
            },
        });
        res.json(result);
    });
    router.post("/companies/:companyId/skills/:skillId/reset", validate(companySkillResetSchema), async (req, res) => {
        const companyId = req.params.companyId;
        const skillId = req.params.skillId;
        await assertCanMutateCompanySkills(req, companyId);
        const before = await svc.getById(companyId, skillId);
        const result = await svc.resetSkill(companyId, skillId, req.body);
        if (!result) {
            res.status(404).json({ error: "Skill not found" });
            return;
        }
        const actor = getActorInfo(req);
        await logActivity(db, {
            companyId,
            actorType: actor.actorType,
            actorId: actor.actorId,
            agentId: actor.agentId,
            runId: actor.runId,
            action: "company.skill_reset",
            entityType: "company_skill",
            entityId: result.id,
            details: {
                slug: result.slug,
                previousOriginHash: before?.metadata?.originHash ?? before?.sourceRef ?? null,
                previousOriginVersion: before?.metadata?.originVersion ?? null,
                newOriginHash: result.metadata?.originHash ?? result.sourceRef,
                newOriginVersion: result.metadata?.originVersion ?? null,
                driftDetected: Boolean(before?.metadata?.userModifiedAt),
                force: Boolean(req.body.force),
                auditVerdict: result.metadata?.auditVerdict ?? null,
            },
        });
        res.json(result);
    });
    return router;
}
//# sourceMappingURL=company-skills.js.map