import {
    Action,
    ActionType,
    FlowOperationRequest,
    flowOperations,
    FlowOperationType,
    FlowVersion,
    FlowVersionState,
    PackageType,
    PieceType,
    StepLocationRelativeToParent,
    Trigger,
    TriggerType,
} from '../../src'
import { _getImportOperations } from '../../src/lib/flows/operations/import-flow'

const flowVersionWithBranching: FlowVersion = {
    id: 'pj0KQ7Aypoa9OQGHzmKDl',
    created: '2023-05-24T00:16:41.353Z',
    updated: '2023-05-24T00:16:41.353Z',
    flowId: 'lod6JEdKyPlvrnErdnrGa',
    updatedBy: '',
    displayName: 'Standup Reminder',
    trigger: {
        name: 'trigger',
        type: TriggerType.PIECE,
        valid: true,
        settings: {
            input: {
                cronExpression: '25 10 * * 0,1,2,3,4',
            },
            packageType: PackageType.REGISTRY,
            pieceType: PieceType.OFFICIAL,
            pieceName: 'schedule',
            pieceVersion: '0.0.2',
            inputUiInfo: {},
            triggerName: 'cron_expression',
        },
        nextAction: {
            name: 'step_1',
            type: 'ROUTER',
            valid: true,
            settings: {
                conditions: [
                    [
                        {
                            operator: 'TEXT_CONTAINS',
                            firstValue: '1',
                            secondValue: '1',
                            caseSensitive: true,
                        },
                    ],
                ],
            },
            nextAction: {
                name: 'step_4',
                type: 'PIECE',
                valid: true,
                settings: {
                    input: {
                        key: '1',
                    },
                    packageType: PackageType.REGISTRY,
                    pieceType: PieceType.OFFICIAL,
                    pieceName: 'store',
                    pieceVersion: '~0.2.6',
                    actionName: 'get',
                    inputUiInfo: {
                        customizedInputs: {},
                    },
                },
                displayName: 'Get',
            },
            displayName: 'Router',
            onFailureAction: {
                name: 'step_3',
                type: 'CODE',
                valid: true,
                settings: {
                    input: {},
                    sourceCode: {
                        code: 'test',
                        packageJson: '{}',
                    },
                },
                displayName: 'Code',
            },
            onSuccessAction: {
                name: 'step_2',
                type: 'PIECE',
                valid: true,
                settings: {
                    input: {
                        content: 'MESSAGE',
                        webhook_url: 'WEBHOOK_URL',
                    },
                    packageType: PackageType.REGISTRY,
                    pieceType: PieceType.OFFICIAL,
                    pieceName: 'discord',
                    pieceVersion: '0.2.1',
                    actionName: 'send_message_webhook',
                    inputUiInfo: {
                        customizedInputs: {},
                    },
                },
                displayName: 'Send Message Webhook',
            },
        },
        displayName: 'Cron Expression',
    },
    connectionIds: [],
    valid: true,
    state: FlowVersionState.DRAFT,
}

function createCodeAction(name: string): Action {
    return {
        name,
        displayName: 'Code',
        type: ActionType.CODE,
        valid: true,
        settings: {
            sourceCode: {
                code: 'test',
                packageJson: '{}',
            },
            input: {},
        },
    }
}
const emptyScheduleFlowVersion: FlowVersion = {
    id: 'pj0KQ7Aypoa9OQGHzmKDl',
    created: '2023-05-24T00:16:41.353Z',
    updated: '2023-05-24T00:16:41.353Z',
    flowId: 'lod6JEdKyPlvrnErdnrGa',
    displayName: 'Standup Reminder',
    updatedBy: '',
    trigger: {
        name: 'trigger',
        type: TriggerType.PIECE,
        valid: true,
        settings: {
            input: {
                cronExpression: '25 10 * * 0,1,2,3,4',
            },
            packageType: PackageType.REGISTRY,
            pieceType: PieceType.OFFICIAL,
            pieceName: 'schedule',
            pieceVersion: '0.0.2',
            inputUiInfo: {},
            triggerName: 'cron_expression',
        },
        displayName: 'Cron Expression',
    },
    valid: true,
    state: FlowVersionState.DRAFT,
    connectionIds: [],
}

describe('Flow Helper', () => {
    it('should lock a flow', () => {
        const operation: FlowOperationRequest = {
            type: FlowOperationType.LOCK_FLOW,
            request: {
                flowId: flowVersionWithBranching.flowId,
            },
        }
        const result = flowOperations.apply(flowVersionWithBranching, operation)
        expect(result.state).toEqual(FlowVersionState.LOCKED)
    })

    it('should delete branch', () => {
        const operation: FlowOperationRequest = {
            type: FlowOperationType.DELETE_ACTION,
            request: {
                names: [flowVersionWithBranching.trigger.nextAction.name],
            },
        }
        const result = flowOperations.apply(flowVersionWithBranching, operation)
        const expectedFlowVersion: FlowVersion = {
            id: 'pj0KQ7Aypoa9OQGHzmKDl',
            updatedBy: '',
            created: '2023-05-24T00:16:41.353Z',
            updated: '2023-05-24T00:16:41.353Z',
            flowId: 'lod6JEdKyPlvrnErdnrGa',
            displayName: 'Standup Reminder',
            trigger: {
                name: 'trigger',
                type: TriggerType.PIECE,
                valid: true,
                settings: {
                    input: {
                        cronExpression: '25 10 * * 0,1,2,3,4',
                    },
                    packageType: PackageType.REGISTRY,
                    pieceType: PieceType.OFFICIAL,
                    pieceName: 'schedule',
                    pieceVersion: '~0.0.2',
                    inputUiInfo: {},
                    triggerName: 'cron_expression',
                },
                displayName: 'Cron Expression',
                nextAction: {
                    name: 'step_4',
                    type: 'PIECE',
                    valid: true,
                    settings: {
                        input: {
                            key: '1',
                        },
                        packageType: PackageType.REGISTRY,
                        pieceType: PieceType.OFFICIAL,
                        pieceName: 'store',
                        pieceVersion: '~0.2.6',
                        actionName: 'get',
                        inputUiInfo: {
                            customizedInputs: {},
                        },
                    },
                    displayName: 'Get',
                },
            },
            valid: true,
            state: FlowVersionState.DRAFT,
            connectionIds: [],
        }
        expect(result).toEqual(expectedFlowVersion)
    })


    it('should add loop step with actions', () => {
        const addBranchRequest: FlowOperationRequest = {
            type: FlowOperationType.ADD_ACTION,
            request: {
                parentStep: 'trigger',
                action: {
                    name: 'step_1',
                    type: ActionType.LOOP_ON_ITEMS,
                    displayName: 'Loop',
                    valid: true,
                    settings: {
                        items: 'items',
                        inputUiInfo: {},
                    },
                },
            },
        }
        const addCodeActionInside: FlowOperationRequest = {
            type: FlowOperationType.ADD_ACTION,
            request: {
                parentStep: 'step_1',
                stepLocationRelativeToParent: StepLocationRelativeToParent.INSIDE_LOOP,
                action: createCodeAction('step_3'),
            },
        }
        const addCodeActionOnAfter: FlowOperationRequest = {
            type: FlowOperationType.ADD_ACTION,
            request: {
                parentStep: 'step_1',
                stepLocationRelativeToParent: StepLocationRelativeToParent.AFTER,
                action: createCodeAction('step_4'),
            },
        }
        let resultFlow = emptyScheduleFlowVersion
        resultFlow = flowOperations.apply(resultFlow, addBranchRequest)
        resultFlow = flowOperations.apply(resultFlow, addCodeActionInside)
        resultFlow = flowOperations.apply(resultFlow, addCodeActionOnAfter)

        const expectedTrigger: Trigger = {
            name: 'trigger',
            type: TriggerType.PIECE,
            valid: true,
            settings: {
                input: {
                    cronExpression: '25 10 * * 0,1,2,3,4',
                },
                packageType: PackageType.REGISTRY,
                pieceType: PieceType.OFFICIAL,
                pieceName: 'schedule',
                pieceVersion: '~0.0.2',
                inputUiInfo: {},
                triggerName: 'cron_expression',
            },
            displayName: 'Cron Expression',
            nextAction: {
                displayName: 'Loop',
                name: 'step_1',
                valid: true,
                type: 'LOOP_ON_ITEMS',
                settings: {
                    items: 'items',
                    inputUiInfo: {},
                },
                firstLoopAction: {
                    displayName: 'Code',
                    name: 'step_3',
                    valid: true,
                    type: 'CODE',
                    settings: {
                        input: {},
                        sourceCode: {
                            code: 'test',
                            packageJson: '{}',
                        },
                    },
                },
                nextAction: {
                    displayName: 'Code',
                    name: 'step_4',
                    valid: true,
                    type: 'CODE',
                    settings: {
                        input: {},
                        sourceCode: {
                            code: 'test',
                            packageJson: '{}',
                        },
                    },
                },
            },
        }
        expect(resultFlow.trigger).toEqual(expectedTrigger)
    })
})

test('Duplicate Flow With Loops using Import', () => {
    const flowVersion: FlowVersion = {
        id: '2XuLcKZWSgKkiHh6RqWXg',
        created: '2023-05-23T00:14:47.809Z',
        updated: '2023-05-23T00:14:47.809Z',
        flowId: 'YGPIPQDfLcPdJ0aJ9AKGb',
        updatedBy: '',
        displayName: 'Flow 1',
        trigger: {
            name: 'trigger',
            type: TriggerType.PIECE,
            valid: true,
            settings: {
                input: {
                    repository: {
                        repo: 'activepieces',
                        owner: 'activepieces',
                    },
                    authentication: '{{connections.github}}',
                },
                packageType: PackageType.REGISTRY,
                pieceType: PieceType.OFFICIAL,
                pieceName: 'github',
                pieceVersion: '0.1.3',
                inputUiInfo: {},
                triggerName: 'trigger_star',
            },
            nextAction: {
                name: 'step_1',
                type: 'LOOP_ON_ITEMS',
                valid: false,
                settings: {
                    items: '',
                    inputUiInfo: {},
                },
                nextAction: {
                    name: 'step_3',
                    type: 'CODE',
                    valid: true,
                    settings: {
                        input: {},
                        sourceCode: {
                            code: 'test',
                            packageJson: '{}',
                        },
                    },
                    displayName: 'Code',
                },
                displayName: 'Loop on Items',
                firstLoopAction: {
                    name: 'step_2',
                    type: 'CODE',
                    valid: true,
                    settings: {
                        input: {},
                        sourceCode: {
                            code: 'test',
                            packageJson: '{}',
                        },
                    },
                    displayName: 'Code',
                },
            },
            displayName: 'Trigger',
        },
        valid: false,
        state: FlowVersionState.DRAFT,
        connectionIds: [],
    }
    const expectedResult: FlowOperationRequest[] = [
        {
            type: FlowOperationType.ADD_ACTION,
            request: {
                parentStep: 'trigger',
                stepLocationRelativeToParent: StepLocationRelativeToParent.AFTER,
                action: {
                    name: 'step_1',
                    type: ActionType.LOOP_ON_ITEMS,
                    valid: false,
                    settings: {
                        items: '',
                        inputUiInfo: {},
                    },
                    displayName: 'Loop on Items',
                },
            },
        },
        {
            type: FlowOperationType.ADD_ACTION,
            request: {
                parentStep: 'step_1',
                stepLocationRelativeToParent: StepLocationRelativeToParent.AFTER,
                action: {
                    name: 'step_3',
                    type: ActionType.CODE,
                    valid: true,
                    settings: {
                        input: {},
                        sourceCode: {
                            code: 'test',
                            packageJson: '{}',
                        },
                    },
                    displayName: 'Code',
                },
            },
        },
        {
            type: FlowOperationType.ADD_ACTION,
            request: {
                parentStep: 'step_1',
                stepLocationRelativeToParent: StepLocationRelativeToParent.INSIDE_LOOP,
                action: {
                    name: 'step_2',
                    type: ActionType.CODE,
                    valid: true,
                    settings: {
                        input: {},
                        sourceCode: {
                            code: 'test',
                            packageJson: '{}',
                        },
                    },
                    displayName: 'Code',
                },
            },
        },
    ]

    const importOperations = _getImportOperations(flowVersion.trigger)
    expect(importOperations).toEqual(expectedResult)
})
