// Copyright (C) CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

/// <reference types="cypress" />

/*
    TODO: Add new test cases
    - After drawing with disabled "autoNext", user should be able to activate and drag/resize object
    - User also should be able to remove activated object with shortcut
    - After removing an object, drawing should start automatically
*/

context('Single object annotation mode', { scrollBehavior: false }, () => {
    const taskName = 'Single object annotation mode';
    const serverFiles = ['images/image_1.jpg', 'images/image_2.jpg', 'images/image_3.jpg'];
    const frameCount = serverFiles.length;

    let taskID = null;
    let jobID = null;

    const rectangleShape = [
        { x: 300, y: 100 },
        { x: 400, y: 400 },
    ];
    const polygonShape = [
        { x: 300, y: 100 },
        { x: 400, y: 400 },
        { x: 400, y: 250 },
        { x: 450, y: 350 },
    ];
    const polylineShape = [
        { x: 300, y: 100 },
        { x: 400, y: 400 },
        { x: 400, y: 250 },
        { x: 450, y: 350 },
        { x: 500, y: 450 },
    ];
    const pointsShape = [
        { x: 300, y: 100 },
        { x: 400, y: 400 },
        { x: 400, y: 250 },
        { x: 450, y: 350 },
    ];
    const ellipseShape = [
        { x: 300, y: 100 },
        { x: 400, y: 400 },
    ];
    const cuboidShape = [
        { x: 300, y: 100 },
        { x: 400, y: 400 },
    ];
    const maskActions = [{
        method: 'brush',
        coordinates: [[300, 300], [700, 300], [700, 700], [300, 700]],
    }];

    function clickPoints(shape) {
        shape.forEach((element) => {
            cy.get('.cvat-canvas-container').click(element.x, element.y);
        });
    }

    function checkFrameNum(frameNum) {
        cy.get('.cvat-player-frame-selector').within(() => {
            cy.get('input[role="spinbutton"]').should('have.value', frameNum);
        });
    }

    function checkSingleShapeModeOpened() {
        cy.get('.cvat-workspace-selector').should('have.text', 'Single shape');
        cy.get('.cvat-canvas-controls-sidebar').should('not.exist');
        cy.get('.cvat-player-frame-selector input').should('be.disabled');

        cy.get('.cvat-single-shape-annotation-sidebar-hint').should('exist');
        cy.get('.cvat-single-shape-annotation-sidebar-ux-hints').should('exist');
        cy.get('#cvat_canvas_wrapper').should('have.css', 'cursor', 'crosshair');
    }

    function openJob(params) {
        cy.visit(`/tasks/${taskID}/jobs/${jobID}`, {
            qs: {
                defaultWorkspace: 'single_shape',
                ...params,
            },
        });
        cy.get('.cvat-canvas-container').should('not.exist');
        cy.get('.cvat-canvas-container').should('exist').and('be.visible');
    }

    function drawObject(creatorFunction) {
        checkSingleShapeModeOpened();

        cy.intercept('PATCH', `/api/jobs/${jobID}/**`).as('submitJob');
        for (let frame = 0; frame < frameCount; frame++) {
            checkFrameNum(frame);
            creatorFunction();
        }

        cy.wait('@submitJob').its('response.statusCode').should('equal', 200);
        cy.get('.cvat-annotation-job-finished-success').should('exist');
        cy.get('.cvat-annotation-job-finished-success').should('not.exist');
    }

    function changeLabel(labelName) {
        cy.get('.cvat-single-shape-annotation-sidebar-label-select').click();
        cy.get('.ant-select-dropdown').not('.ant-select-dropdown-hidden').within(() => {
            cy.get('.ant-select-item-option-content').contains(labelName).click();
        });
    }

    function resetAfterTestCase() {
        cy.removeAnnotations();
        cy.saveJob('PUT');
    }

    before(() => {
        cy.visit('/auth/login');
        cy.login();
        cy.headlessCreateTask({
            labels: [
                { name: 'rectangle_label', attributes: [], type: 'rectangle' },
                { name: 'polygon_label', attributes: [], type: 'polygon' },
                { name: 'polyline_label', attributes: [], type: 'polyline' },
                { name: 'points_label', attributes: [], type: 'points' },
                { name: 'ellipse_label', attributes: [], type: 'ellipse' },
                { name: 'cuboid_label', attributes: [], type: 'cuboid' },
                { name: 'mask_label', attributes: [], type: 'mask' },
            ],
            name: taskName,
            project_id: null,
            source_storage: { location: 'local' },
            target_storage: { location: 'local' },
        }, {
            server_files: serverFiles,
            image_quality: 70,
            use_zip_chunks: true,
            use_cache: true,
            sorting_method: 'lexicographical',
        }).then((response) => {
            taskID = response.taskID;
            [jobID] = response.jobIDs;
        }).then(() => {
            cy.visit(`/tasks/${taskID}/jobs/${jobID}`);
            cy.get('.cvat-canvas-container').should('exist').and('be.visible');
        });
    });

    after(() => {
        cy.logout();
        cy.getAuthKey().then((response) => {
            const authKey = response.body.key;
            cy.request({
                method: 'DELETE',
                url: `/api/tasks/${taskID}`,
                headers: {
                    Authorization: `Token ${authKey}`,
                },
            });
        });
    });

    describe('Tests basic features of single shape annotation mode', () => {
        afterEach(resetAfterTestCase);

        it('Check basic single shape annotation pipeline for polygon', () => {
            openJob({ defaultLabel: 'polygon_label', defaultPointsCount: 4 });
            drawObject(() => clickPoints(polygonShape));
        });

        it('Check basic single shape annotation pipeline for rectangle', () => {
            openJob({ defaultLabel: 'rectangle_label' });
            drawObject(() => clickPoints(rectangleShape));
        });

        it('Check basic single shape annotation pipeline for polyline', () => {
            openJob({ defaultLabel: 'polyline_label', defaultPointsCount: 5 });
            drawObject(() => clickPoints(polylineShape));
        });

        it('Check basic single shape annotation pipeline for ellipse', () => {
            openJob({ defaultLabel: 'ellipse_label' });
            drawObject(() => clickPoints(ellipseShape));
        });

        it('Check basic single shape annotation pipeline for points', () => {
            openJob({ defaultLabel: 'points_label', defaultPointsCount: 4 });
            drawObject(() => clickPoints(pointsShape));
        });

        it('Check basic single shape annotation pipeline for cuboid', () => {
            openJob({ defaultLabel: 'cuboid_label' });
            drawObject(() => clickPoints(cuboidShape));
        });

        it('Check basic single shape annotation pipeline for mask', () => {
            openJob({ defaultLabel: 'mask_label' });
            cy.drawMask(maskActions);
            cy.finishMaskDrawing();
        });
    });

    describe('Tests advanced features of single shape annotation mode', () => {
        afterEach(resetAfterTestCase);

        it('Check single shape annotation mode controls', () => {
            openJob({ defaultLabel: 'polygon_label', defaultPointsCount: 4 });
            checkSingleShapeModeOpened();

            // Skip
            cy.get('.cvat-single-shape-annotation-sidebar-finish-frame-wrapper').within(() => {
                cy.contains('Skip').click();
            });
            checkFrameNum(1);

            // Auto next frame - disabled
            cy.get('.cvat-single-shape-annotation-sidebar-auto-next-frame-checkbox').within(() => {
                cy.get('[type="checkbox"]').uncheck();
            });
            clickPoints(polygonShape);
            checkFrameNum(1);

            // Auto save when finish - disabled
            cy.get('.cvat-player-next-button-empty').click();
            cy.get('.cvat-single-shape-annotation-sidebar-auto-save-checkbox').within(() => {
                cy.get('[type="checkbox"]').uncheck();
            });
            clickPoints(polygonShape);
            cy.get('.cvat-annotation-job-finished-success').should('not.exist');

            // Navigate only on empty frames
            cy.get('.cvat-player-previous-button-empty').click();
            checkFrameNum(0);
            cy.get('.cvat-player-next-button-empty').click();
            checkFrameNum(0);
            cy.get('.cvat-single-shape-annotation-sidebar-navigate-empty-checkbox').within(() => {
                cy.get('[type="checkbox"]').uncheck();
            });
            cy.get('.cvat-player-next-button').click();
            checkFrameNum(1);
            cy.get('.cvat-player-next-button').click();
            checkFrameNum(2);

            cy.saveJob();
        });
    });

    describe('Regression tests', () => {
        afterEach(resetAfterTestCase);

        it('Changing labels in single shape annotation mode', () => {
            openJob({ defaultLabel: 'polygon_label', defaultPointsCount: 4 });
            checkSingleShapeModeOpened();

            const anotherLabelName = 'points_label';
            changeLabel(anotherLabelName);
            clickPoints(pointsShape);

            cy.changeWorkspace('Standard');
            cy.goCheckFrameNumber(0);
            cy.get('#cvat-objects-sidebar-state-item-1').within(() => {
                cy.get('.cvat-objects-sidebar-state-item-label-selector').should('have.text', anotherLabelName);
            });

            cy.saveJob();
        });
    });
});
