import { convertCSSSize } from "../../utils";
import { ControlPose } from "../../types";
import { convertUnitSize } from "@daybrush/utils";

const RADIUS_DIRECTIONS = ["nw", "ne", "se", "sw"] as const;

function calculateRatio(values: number[], size: number) {
    const sumSize = values[0] + values[1];
    const sumRatio = sumSize > size ? size / sumSize : 1;

    values[0] *= sumRatio;
    values[1] = size - values[1] * sumRatio;

    return values;
}
export const HORIZONTAL_RADIUS_ORDER = [1, 2, 5, 6];
export const VERTICAL_RADIUS_ORDER = [0, 3, 4, 7];
export const HORIZONTAL_RADIUS_DIRECTIONS = [1, -1, -1, 1] as const;
export const VERTICAL_RADIUS_DIRECTIONS = [1, 1, -1, -1] as const;

export function getRadiusStyles(
    nextPoses: ControlPose[],
    isRelative: boolean,
    width: number,
    height: number,
    left = 0,
    top = 0,
    right: number = width,
    bottom: number = height,
) {
    const clipStyles: string[] = [];
    let isVertical = false;

    const radiusPoses = nextPoses.filter(pos => !pos.virtual);
    const raws = radiusPoses.map(posInfo => {
        const { horizontal, vertical, pos } = posInfo;

        if (vertical && !isVertical) {
            isVertical = true;
            clipStyles.push("/");
        }

        if (isVertical) {
            const rawPos = Math.max(0, vertical === 1 ? pos[1] - top : bottom - pos[1]);
            clipStyles.push(convertCSSSize(rawPos, height, isRelative));

            return rawPos;
        } else {
            const rawPos = Math.max(0, horizontal === 1 ? pos[0] - left : right - pos[0]);
            clipStyles.push(convertCSSSize(rawPos, width, isRelative));

            return rawPos;
        }
    });

    return {
        radiusPoses,
        styles: clipStyles,
        raws,
    };
}
export function getRadiusRange(controlPoses: ControlPose[]) {
    // [start, length]
    const horizontalRange = [0, 0];
    const verticalRange = [0, 0];
    const length = controlPoses.length;

    for (let i = 0; i < length; ++i) {
        const clipPose = controlPoses[i];

        if (!clipPose.sub) {
            continue;
        }
        if (clipPose.horizontal) {
            if (horizontalRange[1] === 0) {
                horizontalRange[0] = i;
            }
            horizontalRange[1] = i - horizontalRange[0] + 1;
            verticalRange[0] = i + 1;
        }
        if (clipPose.vertical) {
            if (verticalRange[1] === 0) {
                verticalRange[0] = i;
            }
            verticalRange[1] = i - verticalRange[0] + 1;
        }
    }

    return {
        horizontalRange,
        verticalRange,
    };
}
export function getRadiusValues(
    values: string[],
    width: number,
    height: number,
    left: number,
    top: number,
    minCounts: number[] = [0, 0],
    full = false,
): ControlPose[] {
    const splitIndex = values.indexOf("/");
    const splitLength = (splitIndex > -1 ? values.slice(0, splitIndex) : values).length;
    const horizontalValues = values.slice(0, splitLength);
    const verticalValues = values.slice(splitLength + 1);
    const horizontalValuesLength = horizontalValues.length;
    const verticalValuesLength = verticalValues.length;
    const hasVerticalValues = verticalValuesLength > 0;
    const [
        nwValue = "0px",
        neValue = nwValue,
        seValue = nwValue,
        swValue = neValue,
    ] = horizontalValues;
    const [
        wnValue = nwValue,
        enValue = hasVerticalValues ? wnValue : neValue,
        esValue = hasVerticalValues ? wnValue : seValue,
        wsValue = hasVerticalValues ? enValue : swValue,
    ] = verticalValues;

    const horizontalRawPoses = [nwValue, neValue, seValue, swValue].map(pos => convertUnitSize(pos, width));
    const verticalRawPoses = [wnValue, enValue, esValue, wsValue].map(pos => convertUnitSize(pos, height));
    const horizontalPoses = horizontalRawPoses.slice();
    const verticalPoses = verticalRawPoses.slice();

    [horizontalPoses[0], horizontalPoses[1]] = calculateRatio(
        [horizontalPoses[0], horizontalPoses[1]],
        width,
    );
    [horizontalPoses[3], horizontalPoses[2]] = calculateRatio(
        [horizontalPoses[3], horizontalPoses[2]],
        width,
    );
    [verticalPoses[0], verticalPoses[3]] = calculateRatio(
        [verticalPoses[0], verticalPoses[3]], height,
    );
    [verticalPoses[1], verticalPoses[2]] = calculateRatio(
        [verticalPoses[1], verticalPoses[2]], height,
    );

    const nextHorizontalPoses = full
        ? horizontalPoses
        : horizontalPoses.slice(0, Math.max(minCounts[0], horizontalValuesLength));
    const nextVerticalPoses = full
        ? verticalPoses
        : verticalPoses.slice(0, Math.max(minCounts[1], verticalValuesLength));

    return [
        ...nextHorizontalPoses.map((pos, i) => {
            const direction = RADIUS_DIRECTIONS[i];

            return {
                virtual: i >= horizontalValuesLength,
                horizontal: HORIZONTAL_RADIUS_DIRECTIONS[i],
                vertical: 0,
                pos: [left + pos, top + (VERTICAL_RADIUS_DIRECTIONS[i] === -1 ? height : 0)],
                sub: true,
                raw: horizontalRawPoses[i],
                direction,
            };
        }),
        ...nextVerticalPoses.map((pos, i) => {
            const direction = RADIUS_DIRECTIONS[i];

            return {
                virtual: i >= verticalValuesLength,
                horizontal: 0,
                vertical: VERTICAL_RADIUS_DIRECTIONS[i],
                pos: [left + (HORIZONTAL_RADIUS_DIRECTIONS[i] === -1 ? width : 0), top + pos],
                sub: true,
                raw: verticalRawPoses[i],
                direction,
            };
        }),
    ];
}
export function removeRadiusPos(
    controlPoses: ControlPose[],
    poses: number[][],
    index: number,
    startIndex: number,
    length: number = poses.length,
) {
    const {
        horizontalRange,
        verticalRange,
    } = getRadiusRange(controlPoses.slice(startIndex));
    const radiuslIndex = index - startIndex;
    let deleteCount = 0;

    if (radiuslIndex === 0) {
        deleteCount = length;
    } else if (radiuslIndex > 0 && radiuslIndex < horizontalRange[1]) {
        deleteCount = horizontalRange[1] - radiuslIndex;
    } else if (radiuslIndex >= verticalRange[0]) {
        deleteCount = verticalRange[0] + verticalRange[1] - radiuslIndex;
    } else {
        return;
    }
    controlPoses.splice(index, deleteCount);
    poses.splice(index, deleteCount);
}
export function addRadiusPos(
    controlPoses: ControlPose[],
    poses: number[][],
    startIndex: number,
    horizontalIndex: number,
    verticalIndex: number,
    distX: number,
    distY: number,
    right: number,
    bottom: number,
    left = 0,
    top = 0,
) {
    const {
        horizontalRange,
        verticalRange,
    } = getRadiusRange(controlPoses.slice(startIndex));
    if (horizontalIndex > -1) {
        const radiusX = HORIZONTAL_RADIUS_DIRECTIONS[horizontalIndex] === 1
            ? distX - left
            : right - distX;
        for (let i = horizontalRange[1]; i <= horizontalIndex; ++i) {
            const y = VERTICAL_RADIUS_DIRECTIONS[i] === 1 ? top : bottom;
            let x = 0;
            if (horizontalIndex === i) {
                x = distX;
            } else if (i === 0) {
                x = left + radiusX;
            } else if (HORIZONTAL_RADIUS_DIRECTIONS[i] === -1) {
                x = right - (poses[startIndex][0] - left);
            }
            controlPoses.splice(startIndex + i, 0, {
                horizontal: HORIZONTAL_RADIUS_DIRECTIONS[i],
                vertical: 0,
                pos: [x, y],
            });
            poses.splice(startIndex + i, 0, [x, y]);

            if (i === 0) {
                break;
            }
        }
    } else if (verticalIndex > - 1) {
        const radiusY = VERTICAL_RADIUS_DIRECTIONS[verticalIndex] === 1
            ? distY - top
            : bottom - distY;
        if (horizontalRange[1] === 0 && verticalRange[1] === 0) {
            const pos = [
                left + radiusY,
                top,
            ];
            controlPoses.push({
                horizontal: HORIZONTAL_RADIUS_DIRECTIONS[0],
                vertical: 0,
                pos,
            });
            poses.push(pos);
        }

        const startVerticalIndex = verticalRange[0];
        for (let i = verticalRange[1]; i <= verticalIndex; ++i) {
            const x = HORIZONTAL_RADIUS_DIRECTIONS[i] === 1 ? left : right;
            let y = 0;
            if (verticalIndex === i) {
                y = distY;
            } else if (i === 0) {
                y = top + radiusY;
            } else if (VERTICAL_RADIUS_DIRECTIONS[i] === 1) {
                y = poses[startIndex + startVerticalIndex][1];
            } else if (VERTICAL_RADIUS_DIRECTIONS[i] === -1) {
                y = bottom - (poses[startIndex + startVerticalIndex][1] - top);
            }
            controlPoses.push({
                horizontal: 0,
                vertical: VERTICAL_RADIUS_DIRECTIONS[i],
                pos: [x, y],
            });
            poses.push([x, y]);
            if (i === 0) {
                break;
            }
        }
    }
}
export function splitRadiusPoses(
    controlPoses: ControlPose[],
    raws: number[] = controlPoses.map(pos => pos.raw!),
) {
    const horizontals = controlPoses
        .map((pos, i) => pos.horizontal ? raws[i] : null).filter(pos => pos != null) as number[];
    const verticals = controlPoses
        .map((pos, i) => pos.vertical ? raws[i] : null).filter(pos => pos != null) as number[];

    return {
        horizontals,
        verticals,
    };
}
