import type { AnchorValue, Anchors, Canvas } from '@/types/layout';

export type Rect = { x: number; y: number; width: number; height: number };

const resolveValue = (av: AnchorValue | undefined, base: number): number | null => {
    if (!av) return null;
    if (av.type === 'auto') return null;
    if (av.type === 'percent') return (av.value / 100) * base;
    return av.value;
};

const resolveAxis = (
    start: AnchorValue | undefined,
    end: AnchorValue | undefined,
    size: AnchorValue | undefined,
    base: number,
    fallbackSize: number,
): { position: number; length: number } => {
    const s = resolveValue(start, base);
    const e = resolveValue(end, base);
    const w = resolveValue(size, base);

    if (s != null && w != null) {
        const align = start?.type !== 'auto' ? start?.align : undefined;
        if (align === 'center') return { position: s - w / 2, length: w };
        if (align === 'end') return { position: s - w, length: w };
        return { position: s, length: w };
    }
    if (e != null && w != null) {
        return { position: base - e - w, length: w };
    }
    if (s != null && e != null) {
        return { position: s, length: Math.max(0, base - s - e) };
    }
    if (w != null) {
        return { position: (base - w) / 2, length: w };
    }
    if (s != null) return { position: s, length: fallbackSize };
    if (e != null) return { position: base - e - fallbackSize, length: fallbackSize };
    return { position: (base - fallbackSize) / 2, length: fallbackSize };
};

export function resolveAnchors(anchors: Anchors, canvas: Canvas): Rect {
    const fallbackW = Math.round(canvas.width * 0.4);
    const fallbackH = Math.round(canvas.height * 0.12);
    const h = resolveAxis(anchors.left, anchors.right, anchors.width, canvas.width, fallbackW);
    const v = resolveAxis(anchors.top, anchors.bottom, anchors.height, canvas.height, fallbackH);
    return { x: h.position, y: v.position, width: h.length, height: v.length };
}

/**
 * Produce a new Anchors object from a node's pixel rect, preserving the unit
 * system (percent vs px) of the previous anchors. Called after drag/transform.
 */
export function rectToAnchors(rect: Rect, canvas: Canvas, previous: Anchors): Anchors {
    const keepPercent = (av: AnchorValue | undefined): boolean =>
        av?.type === 'percent' || av == null;

    const alignOf = (av: AnchorValue | undefined): 'start' | 'center' | 'end' | undefined =>
        av && av.type !== 'auto' ? av.align : undefined;

    const toValue = (
        av: AnchorValue | undefined,
        px: number,
        base: number,
    ): AnchorValue => {
        const align = alignOf(av);
        if (keepPercent(av)) {
            return { type: 'percent', value: +((px / base) * 100).toFixed(3), align };
        }
        return { type: 'px', value: Math.round(px), align };
    };

    const next: Anchors = {};
    const hasLeft = previous.left != null && previous.left.type !== 'auto';
    const hasRight = previous.right != null && previous.right.type !== 'auto';
    const hasTop = previous.top != null && previous.top.type !== 'auto';
    const hasBottom = previous.bottom != null && previous.bottom.type !== 'auto';

    if (hasLeft || !hasRight) {
        const align = previous.left?.type !== 'auto' ? previous.left?.align : undefined;
        const px = align === 'center' ? rect.x + rect.width / 2 : align === 'end' ? rect.x + rect.width : rect.x;
        next.left = toValue(previous.left, px, canvas.width);
    }
    if (hasRight) {
        next.right = toValue(previous.right, canvas.width - rect.x - rect.width, canvas.width);
    }
    if (hasTop || !hasBottom) {
        const align = previous.top?.type !== 'auto' ? previous.top?.align : undefined;
        const px = align === 'center' ? rect.y + rect.height / 2 : align === 'end' ? rect.y + rect.height : rect.y;
        next.top = toValue(previous.top, px, canvas.height);
    }
    if (hasBottom) {
        next.bottom = toValue(previous.bottom, canvas.height - rect.y - rect.height, canvas.height);
    }
    next.width = toValue(previous.width, rect.width, canvas.width);
    next.height = toValue(previous.height, rect.height, canvas.height);
    return next;
}
