import {describe, test, expect} from 'vitest';
import Point from '@mapbox/point-geometry';
import {getAnchors, getCenterAnchor} from './get_anchors.ts';
import {type PositionedIcon, type Shaping} from './shaping.ts';

const TILE_EXTENT = 4096;

describe('getAnchors', () => {
    const nonContinuedLine = [];
    for (let i = 1; i < 11; i++) {
        nonContinuedLine.push(new Point(1, i));
    }

    const continuedLine = [];
    for (let j = 0; j < 10; j++) {
        continuedLine.push(new Point(1, j));
    }

    const smallSpacing = 2;
    const bigSpacing = 3;

    const shapedText = {left: -1, right: 1, top: -0.5, bottom: 0.5} as Shaping;
    const shapedIcon = {left: -0.5, right: 0.5, top: -0.25, bottom: 0.25} as PositionedIcon;
    const labelLength = Math.max(
        shapedText ? shapedText.right - shapedText.left : 0,
        shapedIcon ? shapedIcon.right - shapedIcon.left : 0);

    const glyphSize = 0.1;

    test('non-continued line with short labels', () => {
        const anchors = getAnchors(nonContinuedLine, bigSpacing, Math.PI, shapedText, shapedIcon, glyphSize, 1, 1, TILE_EXTENT);

        expect(anchors).toEqual([
            {x: 1, y: 2, angle: 1.5707963267948966, segment: 1},
            {x: 1, y: 5, angle: 1.5707963267948966, segment: 4},
            {x: 1, y: 8, angle: 1.5707963267948966, segment: 7}]);

        expect(
            labelLength / 2 + 1 <= anchors[0].y && anchors[0].y < labelLength / 2 + 3 * glyphSize + 1
        ).toBeTruthy();

    });

    test('non-continued line with long labels', () => {
        const anchors = getAnchors(nonContinuedLine, smallSpacing, Math.PI, shapedText, shapedIcon, glyphSize, 1, 1, TILE_EXTENT);

        expect(anchors).toEqual([
            {x: 1, y: 2, angle: 1.5707963267948966, segment: 1},
            {x: 1, y: 5, angle: 1.5707963267948966, segment: 3},
            {x: 1, y: 7, angle: 1.5707963267948966, segment: 6}]);

    });

    test('continued line with short labels', () => {
        const anchors = getAnchors(continuedLine, bigSpacing, Math.PI, shapedText, shapedIcon, glyphSize, 1, 1, TILE_EXTENT);

        expect(anchors).toEqual([
            {x: 1, y: 2, angle: 1.5707963267948966, segment: 1},
            {x: 1, y: 5, angle: 1.5707963267948966, segment: 4},
            {x: 1, y: 8, angle: 1.5707963267948966, segment: 7}]);

    });

    test('continued line with long labels', () => {
        const anchors = getAnchors(continuedLine, smallSpacing, Math.PI, shapedText, shapedIcon, glyphSize, 1, 1, TILE_EXTENT);

        expect(anchors).toEqual([
            {x: 1, y: 1, angle: 1.5707963267948966, segment: 1},
            {x: 1, y: 4, angle: 1.5707963267948966, segment: 3},
            {x: 1, y: 6, angle: 1.5707963267948966, segment: 6}]);

    });

    test('overscaled anchors contain all anchors in parent', () => {
        const anchors = getAnchors(nonContinuedLine, bigSpacing, Math.PI, shapedText, shapedIcon, glyphSize, 1, 1, TILE_EXTENT);
        const childAnchors = getAnchors(nonContinuedLine, bigSpacing / 2, Math.PI, shapedText, shapedIcon, glyphSize, 0.5, 2, TILE_EXTENT);
        for (const anchor of anchors) {
            let found = false;
            for (const childAnchor of childAnchors) {
                if (anchor.equals(childAnchor)) {
                    found = true;
                    break;
                }
            }
            expect(found).toBeTruthy();
        }
    });

    test('use middle point as a fallback position for short non-continued lines', () => {
        const line = [new Point(1, 1), new Point(1, 3.1)];
        const anchors = getAnchors(line, 2, Math.PI, shapedText, shapedIcon, glyphSize, 1, 1, TILE_EXTENT);
        expect(anchors).toEqual([
            {x: 1, y: 2, angle: 1.5707963267948966, segment: 0}]);
    });

    test('getCenterAnchor', () => {
        const line = [new Point(1, 1), new Point(1, 3.1), new Point(3, 6), new Point(4, 7)];
        const anchor = getCenterAnchor(line, Math.PI, shapedText, shapedIcon, glyphSize, 1);
        expect(anchor).toEqual({x: 2, y: 4, angle: 0.9670469933974603, segment: 1});
    });

    test('getCenterAnchor with center outside tile bounds', () => {
        const line = [new Point(-10, -10), new Point(5, 5)];
        const anchor = getCenterAnchor(line, Math.PI, shapedText, shapedIcon, glyphSize, 1);
        expect(anchor).toEqual({x: -2, y: -2, angle: 0.7853981633974483, segment: 0});
    });

    test('getCenterAnchor failing maxAngle test', () => {
        const line = [new Point(1, 1), new Point(1, 3), new Point(3, 3)];
        const anchor = getCenterAnchor(line, Math.PI / 4, shapedText, shapedIcon, glyphSize, 1);
        expect(anchor).toBeFalsy();
    });
});
