import { Args, Flags } from '@oclif/core';
import { autoExportToBoard, PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
import { styles } from '../../lib/styles.js';
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
/**
 * Infer entity type from ID prefix
 */
function inferEntityType(id) {
    const upper = id.toUpperCase();
    if (upper.startsWith('TKT-'))
        return 'ticket';
    if (upper.startsWith('SPEC-'))
        return 'spec';
    if (upper.startsWith('EPIC-'))
        return 'epic';
    return null;
}
export default class LinkCreate extends PMOCommand {
    static description = 'Create a link (dependency) between two entities';
    static examples = [
        '<%= config.bin %> <%= command.id %> TKT-001 TKT-002 --type blocks    # TKT-001 is blocked by TKT-002',
        '<%= config.bin %> <%= command.id %> TKT-001 TKT-002 --type relates   # TKT-001 relates to TKT-002',
        '<%= config.bin %> <%= command.id %> SPEC-001 SPEC-002 --type depends # SPEC-001 depends on SPEC-002',
        '<%= config.bin %> <%= command.id %> EPIC-001 EPIC-002 --type blocks  # EPIC-001 is blocked by EPIC-002',
    ];
    static args = {
        from: Args.string({
            description: 'Source entity ID (TKT-xxx, SPEC-xxx, or EPIC-xxx)',
            required: true,
        }),
        to: Args.string({
            description: 'Target entity ID',
            required: true,
        }),
    };
    static flags = {
        ...pmoBaseFlags,
        type: Flags.string({
            char: 't',
            description: 'Link type',
            options: ['blocks', 'relates', 'duplicates', 'depends'],
            required: true,
        }),
    };
    async execute() {
        const { args, flags } = await this.parse(LinkCreate);
        const jsonMode = shouldOutputJson(flags);
        const handleError = (code, message) => {
            if (jsonMode) {
                outputErrorAsJson(code, message, createMetadata('link create', flags));
                this.exit(1);
            }
            this.error(message);
        };
        const fromType = inferEntityType(args.from);
        const toType = inferEntityType(args.to);
        if (!fromType) {
            return handleError('INVALID_FROM_ID', `Cannot infer entity type from "${args.from}". Use TKT-, SPEC-, or EPIC- prefix.`);
        }
        if (!toType) {
            return handleError('INVALID_TO_ID', `Cannot infer entity type from "${args.to}". Use TKT-, SPEC-, or EPIC- prefix.`);
        }
        if (fromType !== toType) {
            return handleError('TYPE_MISMATCH', `Cannot link different entity types: ${fromType} and ${toType}`);
        }
        const linkType = flags.type;
        // Validate link type for entity type
        // Tickets: blocks, relates_to, duplicates
        // Specs: depends_on, relates_to, duplicates (no blocks)
        // Epics: blocks, relates_to, duplicates (no depends)
        if (fromType === 'spec' && linkType === 'blocks') {
            return handleError('INVALID_LINK_TYPE', 'Specs do not support "blocks" link type. Use "depends" instead.');
        }
        if (fromType === 'epic' && linkType === 'depends') {
            return handleError('INVALID_LINK_TYPE', 'Epics do not support "depends" link type. Use "blocks" instead.');
        }
        if (fromType === 'ticket' && linkType === 'depends') {
            return handleError('INVALID_LINK_TYPE', 'Tickets do not support "depends" link type. Use "blocks" instead.');
        }
        // Map the link type to the storage dependency type
        const dependencyType = linkType === 'relates' ? 'relates_to' :
            linkType === 'depends' ? 'depends_on' : linkType;
        try {
            if (fromType === 'ticket') {
                const ticket = await this.storage.getTicket(args.from);
                if (!ticket)
                    return handleError('FROM_NOT_FOUND', `Ticket not found: ${args.from}`);
                const targetTicket = await this.storage.getTicket(args.to);
                if (!targetTicket)
                    return handleError('TO_NOT_FOUND', `Ticket not found: ${args.to}`);
                await this.storage.createTicketDependency(args.from, args.to, dependencyType);
                await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
                this.log(styles.success(`\n✅ Link created: ${styles.emphasis(args.from)} → ${styles.emphasis(args.to)} (${linkType})`));
                this.log(styles.muted(`   ${ticket.title}`));
                this.log(styles.muted(`   ${linkType}: ${targetTicket.title}`));
            }
            else if (fromType === 'spec') {
                const spec = await this.storage.getSpec(args.from);
                if (!spec)
                    return handleError('FROM_NOT_FOUND', `Spec not found: ${args.from}`);
                const targetSpec = await this.storage.getSpec(args.to);
                if (!targetSpec)
                    return handleError('TO_NOT_FOUND', `Spec not found: ${args.to}`);
                await this.storage.createSpecDependency(args.from, args.to, dependencyType);
                this.log(styles.success(`\n✅ Link created: ${styles.emphasis(args.from)} → ${styles.emphasis(args.to)} (${linkType})`));
                this.log(styles.muted(`   ${spec.title}`));
                this.log(styles.muted(`   ${linkType}: ${targetSpec.title}`));
            }
            else if (fromType === 'epic') {
                const epic = await this.storage.getEpic(args.from);
                if (!epic)
                    return handleError('FROM_NOT_FOUND', `Epic not found: ${args.from}`);
                const targetEpic = await this.storage.getEpic(args.to);
                if (!targetEpic)
                    return handleError('TO_NOT_FOUND', `Epic not found: ${args.to}`);
                await this.storage.createEpicDependency(args.from, args.to, dependencyType);
                await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
                this.log(styles.success(`\n✅ Link created: ${styles.emphasis(args.from)} → ${styles.emphasis(args.to)} (${linkType})`));
                this.log(styles.muted(`   ${epic.title}`));
                this.log(styles.muted(`   ${linkType}: ${targetEpic.title}`));
            }
        }
        catch (error) {
            if (error instanceof Error) {
                if (error.message.includes('already exists')) {
                    return handleError('ALREADY_EXISTS', 'Link already exists');
                }
                if (error.message.includes('self-dependency')) {
                    return handleError('SELF_LINK', 'Cannot create self-link');
                }
            }
            throw error;
        }
    }
}
//# sourceMappingURL=create.js.map