import { Utils } from '@tldraw/core';
import Vec from '@tldraw/vec';
import type { ShapeStyles } from '@toeverything/components/board-types';
import getStroke, { getStrokePoints } from 'perfect-freehand';
import { getOffsetPolygon, getShapeStyle } from '../shared';

export function getTrianglePoints(size: number[], offset = 0, rotation = 0) {
    const [w, h] = size;
    let points = [
        [w / 2, 0],
        [w, h],
        [0, h],
    ];
    if (offset) points = getOffsetPolygon(points, offset);
    if (rotation)
        points = points.map(pt => Vec.rotWith(pt, [w / 2, h / 2], rotation));

    return points;
}

export function getTriangleCentroid(size: number[]) {
    const [w, h] = size;
    const points = [
        [w / 2, 0],
        [w, h],
        [0, h],
    ];
    return [
        (points[0][0] + points[1][0] + points[2][0]) / 3,
        (points[0][1] + points[1][1] + points[2][1]) / 3,
    ];
}

function getTriangleDrawPoints(
    id: string,
    size: number[],
    strokeWidth: number
) {
    const [w, h] = size;
    const getRandom = Utils.rng(id);
    // Random corner offsets
    const offsets = Array.from(Array(3)).map(() => {
        return [
            getRandom() * strokeWidth * 0.75,
            getRandom() * strokeWidth * 0.75,
        ];
    });
    // Corners
    const corners = [
        Vec.add([w / 2, 0], offsets[0]),
        Vec.add([w, h], offsets[1]),
        Vec.add([0, h], offsets[2]),
    ];
    // Which side to start drawing first
    const rm = Math.round(Math.abs(getRandom() * 2 * 3));
    // Number of points per side
    // Inset each line by the corner radii and let the freehand algo
    // interpolate points for the corners.
    const lines = Utils.rotateArray(
        [
            Vec.pointsBetween(corners[0], corners[1], 32),
            Vec.pointsBetween(corners[1], corners[2], 32),
            Vec.pointsBetween(corners[2], corners[0], 32),
        ],
        rm
    );
    // For the final points, include the first half of the first line again,
    // so that the line wraps around and avoids ending on a sharp corner.
    // This has a bit of finesse and magic—if you change the points between
    // function, then you'll likely need to change this one too.
    const points = [...lines.flat(), ...lines[0]];
    return {
        points,
    };
}

function getDrawStrokeInfo(id: string, size: number[], style: ShapeStyles) {
    const { strokeWidth } = getShapeStyle(style);
    const { points } = getTriangleDrawPoints(id, size, strokeWidth);
    const options = {
        size: strokeWidth,
        thinning: 0.65,
        streamline: 0.3,
        smoothing: 1,
        simulatePressure: false,
        last: true,
    };
    return { points, options };
}

export function getTrianglePath(
    id: string,
    size: number[],
    style: ShapeStyles
) {
    const { points, options } = getDrawStrokeInfo(id, size, style);
    const stroke = getStroke(points, options);
    return Utils.getSvgPathFromStroke(stroke);
}

// eslint-disable-next-line @typescript-eslint/naming-convention
export function getTriangleIndicatorPathTDSnapshot(
    id: string,
    size: number[],
    style: ShapeStyles
) {
    const { points, options } = getDrawStrokeInfo(id, size, style);
    const strokePoints = getStrokePoints(points, options);
    return Utils.getSvgPathFromStroke(
        strokePoints.map(pt => pt.point.slice(0, 2)),
        false
    );
}
