import { Link } from '@inertiajs/react';
import { ChevronRight } from 'lucide-react';
import { cn } from '@/lib/utils';
import type { PipelineStage } from '@/types';
import { toneClasses } from './tone';

type Stage = Pick<
    PipelineStage,
    'value' | 'label' | 'group' | 'group_label' | 'color' | 'order' | 'waiting_on'
> & { count?: number };

/**
 * The whole installation process at a glance.
 *
 * Stages are grouped into the six phases of an Australian solar job, each
 * phase colour coded, and the bar shows the stage's load relative to the
 * busiest stage so the shape of the pipeline is readable without a chart.
 */
export function PipelineBoard({
    stages,
    hrefFor,
    className,
    showWaitingOn = true,
}: {
    stages: Stage[];
    hrefFor?: (stage: Stage) => string;
    className?: string;
    showWaitingOn?: boolean;
}) {
    const groups: Array<{
        key: string;
        label: string;
        color: string;
        stages: Stage[];
        total: number;
    }> = [];

    stages.forEach((stage) => {
        let group = groups.find((candidate) => candidate.key === stage.group);

        if (!group) {
            group = {
                key: stage.group,
                label: stage.group_label,
                color: stage.color,
                stages: [],
                total: 0,
            };
            groups.push(group);
        }

        group.stages.push(stage);
        group.total += stage.count ?? 0;
    });

    const maxCount = Math.max(
        1,
        ...stages.map((stage) => stage.count ?? 0),
    );

    return (
        <div
            className={cn(
                // Three phases across, then a second row. Six across fits the
                // phases on one screen but leaves each about 190px wide, which
                // clipped the stage names to "Lead /..." and the phase
                // headings to "Compliance and conne...". `items-start` lets a
                // phase with two stages end where its stages end, instead of
                // stretching to the height of the tallest phase beside it.
                'grid items-start gap-3 sm:grid-cols-2 xl:grid-cols-3',
                className,
            )}
        >
            {groups.map((group) => (
                <div
                    key={group.key}
                    className="bg-surface/60 rounded-lg p-2.5 ring-1 ring-hairline"
                >
                    <div className="flex items-center justify-between gap-2 px-1 pb-2">
                        <span className="flex min-w-0 items-center gap-1.5">
                            <span
                                aria-hidden
                                className={cn(
                                    'size-1.5 shrink-0 rounded-full',
                                    toneClasses(group.color).dot,
                                )}
                            />
                            <span className="text-xs leading-snug font-semibold tracking-tight">
                                {group.label}
                            </span>
                        </span>
                        <span className="crm-num text-muted-foreground text-xs">
                            {group.total}
                        </span>
                    </div>

                    <ul className="space-y-0.5">
                        {group.stages.map((stage) => {
                            const count = stage.count ?? 0;
                            const width = Math.round((count / maxCount) * 100);
                            const classes = toneClasses(stage.color);

                            const row = (
                                <>
                                    {/* The stage name and what it is waiting
                                        on are stacked, not side by side: the
                                        two competing for one line squeezed the
                                        name into an ellipsis on every phase. */}
                                    <span className="min-w-0 flex-1">
                                        <span className="block text-xs leading-snug">
                                            {stage.label}
                                        </span>
                                        {showWaitingOn && stage.waiting_on ? (
                                            <span className="text-muted-foreground/80 mt-0.5 block text-[11px] leading-snug">
                                                {stage.waiting_on}
                                            </span>
                                        ) : null}
                                    </span>
                                    <span className="crm-num w-6 shrink-0 text-right text-xs font-medium">
                                        {count}
                                    </span>
                                </>
                            );

                            const inner = (
                                <>
                                    <span
                                        aria-hidden
                                        className={cn(
                                            'absolute inset-y-1 left-0 w-0.5 rounded-full',
                                            count > 0
                                                ? classes.bar
                                                : 'bg-transparent',
                                        )}
                                    />
                                    <span
                                        aria-hidden
                                        className={cn(
                                            'absolute inset-y-0 left-0 opacity-[0.07] transition-all',
                                            count > 0 ? classes.bar : 'bg-transparent',
                                        )}
                                        style={{ width: `${width}%` }}
                                    />
                                    <span className="relative flex w-full items-start gap-2 py-1.5 pr-2 pl-2.5">
                                        {row}
                                    </span>
                                </>
                            );

                            return (
                                <li key={stage.value}>
                                    {hrefFor ? (
                                        <Link
                                            href={hrefFor(stage)}
                                            title={`${stage.label} — ${stage.waiting_on}`}
                                            className="hover:bg-accent relative flex items-center overflow-hidden rounded-md transition-colors"
                                        >
                                            {inner}
                                        </Link>
                                    ) : (
                                        <div
                                            title={`${stage.label} — ${stage.waiting_on}`}
                                            className="relative flex items-center overflow-hidden rounded-md"
                                        >
                                            {inner}
                                        </div>
                                    )}
                                </li>
                            );
                        })}
                    </ul>
                </div>
            ))}
        </div>
    );
}

/**
 * Where one job sits in the process: the phases it has cleared, the phase it
 * is in, and what it is waiting on. Used on the job page and anywhere a single
 * job needs its position explained.
 */
export function StageRail({
    stages,
    currentStatus,
    progress,
    className,
}: {
    stages: Stage[];
    currentStatus: string;
    progress?: number | null;
    className?: string;
}) {
    const phases: Array<{
        key: string;
        label: string;
        color: string;
        firstOrder: number;
        lastOrder: number;
    }> = [];

    stages.forEach((stage) => {
        const last = phases[phases.length - 1];

        if (last && last.key === stage.group) {
            last.lastOrder = stage.order;
            return;
        }

        phases.push({
            key: stage.group,
            label: stage.group_label,
            color: stage.color,
            firstOrder: stage.order,
            lastOrder: stage.order,
        });
    });

    const current = stages.find((stage) => stage.value === currentStatus);
    const currentOrder = current?.order ?? 0;

    return (
        <div className={cn('space-y-3', className)}>
            {progress !== null && progress !== undefined ? (
                <div className="flex items-baseline justify-between gap-3">
                    <span className="crm-label">Progress</span>
                    <span className="crm-num text-sm font-semibold">
                        {progress}%
                    </span>
                </div>
            ) : null}

            <ol className="flex items-stretch gap-1.5">
                {phases.map((phase) => {
                    const isDone = phase.lastOrder < currentOrder;
                    const isCurrent =
                        currentOrder >= phase.firstOrder &&
                        currentOrder <= phase.lastOrder;
                    const classes = toneClasses(phase.color);

                    return (
                        <li key={phase.key} className="min-w-0 flex-1">
                            <span
                                aria-hidden
                                className={cn(
                                    'block h-1.5 rounded-full',
                                    isCurrent
                                        ? classes.bar
                                        : isDone
                                          ? classes.bar
                                          : 'bg-muted',
                                    isDone && 'opacity-40',
                                )}
                            />
                            <span
                                className={cn(
                                    'mt-1.5 block truncate text-[11px]',
                                    isCurrent
                                        ? 'text-foreground font-semibold'
                                        : 'text-muted-foreground',
                                )}
                                title={phase.label}
                            >
                                {phase.label}
                            </span>
                        </li>
                    );
                })}
            </ol>

            {current ? (
                <p className="text-muted-foreground flex items-center gap-1.5 text-xs">
                    <span className="text-foreground font-medium">
                        {current.label}
                    </span>
                    <ChevronRight className="size-3" />
                    waiting on {current.waiting_on}
                </p>
            ) : null}
        </div>
    );
}

/**
 * A single phase label, for filters and legends.
 */
export function PhaseBadge({
    label,
    color,
    count,
}: {
    label: string;
    color: string;
    count?: number;
}) {
    const classes = toneClasses(color);

    return (
        <span
            className={cn(
                'inline-flex items-center gap-1.5 rounded-md px-2 py-0.5 text-xs font-medium',
                classes.pill,
            )}
        >
            {label}
            {count !== undefined ? (
                <span className="crm-num opacity-70">{count}</span>
            ) : null}
        </span>
    );
}
