import DOMPurify from 'dompurify';
import { ArrowRight, BadgeCheck, Mail } from 'lucide-react';
import type { CSSProperties, ReactNode } from 'react';
import { badge, type Palette } from '@/components/proposal/palette';
import { cn } from '@/lib/utils';

/**
 * Shared design elements of the client proposal (pitch-deck look): near-white pages, flat soft-grey,
 * dark and brand-colour cards, large medium-weight sans headings with a brand highlight on the last
 * word, "// label" eyebrows, numbered tiles and pill buttons.
 */
export const SHADOW = 'none';
export type Align = 'left' | 'center' | 'right';
export const pad2 = (n: number) => String(n).padStart(2, '0');
export const initials = (name: string) => name.split(/\s+/).filter(Boolean).map((w) => w[0]).slice(0, 2).join('').toUpperCase();

export type BrandCompany = { name: string; website: string | null; logo_url: string | null };

export function Brand({ p, hf, company }: { p: Palette; hf: CSSProperties; company: BrandCompany }) {
    // The company logo on every page (the name is only shown until a logo is uploaded in Company settings).
    if (company.logo_url) return <img src={company.logo_url} alt={company.name} className="h-auto max-h-[76px] w-[230px] object-contain object-left" />;
    return (
        <span className="flex items-center gap-2">
            <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-[9px] text-[12px] font-semibold" style={{ background: p.dark, color: p.onDark, ...hf }} aria-hidden>
                {initials(company.name)}
            </span>
            <span className="min-w-0 leading-tight">
                <span className="block truncate text-[14px] font-semibold" style={{ ...hf, color: p.text }}>{company.name}</span>
                {company.website && <a href={webHref(company.website)} className="block truncate text-[10.5px] hover:underline" style={{ color: p.muted }}>{company.website.replace(/^https?:\/\//, '')}</a>}
            </span>
        </span>
    );
}

/** Large medium-weight sans heading. `icon` is accepted for compatibility and not drawn. */
export function Heading({ p, hf, text, size, as: Tag = 'h2', align = 'left', color }: {
    p: Palette; hf: CSSProperties; text: string; size: number; icon?: typeof BadgeCheck; as?: 'h1' | 'h2' | 'h3'; align?: Align; color?: string;
}) {
    return (
        <Tag className="font-medium" style={{ ...hf, fontSize: size, lineHeight: 1.12, letterSpacing: '-0.025em', color: color ?? p.text, textAlign: align }}>{text}</Tag>
    );
}

/** Small "// label" eyebrow, the slashes in the brand colour. */
export function Eyebrow({ p, hf, children, className }: { p: Palette; hf: CSSProperties; children: ReactNode; className?: string }) {
    return (
        <span className={cn('inline-flex max-w-full items-center gap-1.5 text-[12px] font-medium', className)} style={{ ...hf, color: p.text }}>
            <span style={{ color: p.accent }} aria-hidden>//</span><span className="truncate">{children}</span>
        </span>
    );
}

/** A numbered tile ("01.") in the brand colours: primary, dark, secondary in turn. */
export function NumberTile({ p, hf, n, size = 40 }: { p: Palette; hf: CSSProperties; n: number; size?: number }) {
    return (
        <span className="inline-flex shrink-0 items-center justify-center rounded-[10px] font-medium tabular-nums"
            style={{ ...badge(p, n - 1), ...hf, width: size, height: size, fontSize: size * 0.36 }}>{pad2(n)}.</span>
    );
}

/** A rounded-square icon tile in the brand colours. */
export function IconTile({ p, icon: Icon, n = 0, size = 36 }: { p: Palette; icon: typeof BadgeCheck; n?: number; size?: number }) {
    return (
        <span className="inline-flex shrink-0 items-center justify-center rounded-[9px]" style={{ ...badge(p, n), width: size, height: size }} aria-hidden>
            <Icon style={{ width: size * 0.46, height: size * 0.46 }} strokeWidth={2} />
        </span>
    );
}

/** Eyebrow label ("// Proposal SD-1042"). Kept under its old name; no gradient pill. */
export function Chip({ p, hf, children }: { p: Palette; hf: CSSProperties; children: ReactNode }) {
    return <Eyebrow p={p} hf={hf}>{children}</Eyebrow>;
}

export function Avatar({ p, hf, text, photo, light = false, accent = false, size = 40 }: {
    p: Palette; hf: CSSProperties; text: string; photo?: string | null; light?: boolean; accent?: boolean; size?: number;
}) {
    const style: CSSProperties = accent ? { background: p.accent, color: p.onAccent } : light ? { background: p.second, color: p.onSecond } : { background: p.dark, color: p.onDark };
    return (
        <span className="flex shrink-0 items-center justify-center overflow-hidden rounded-full text-[11px] font-semibold ring-[3px]"
            style={{ ...style, ...hf, width: size, height: size, '--tw-ring-color': p.page } as CSSProperties}>
            {photo ? <img src={photo} alt="" className="h-full w-full object-cover" /> : text}
        </span>
    );
}

/** A price, always in charcoal (one colour for all pricing). */
export function Amount({ p, hf, value, size }: { p: Palette; hf: CSSProperties; value: string; size: number; accent?: boolean }) {
    return <span className="font-semibold tabular-nums" style={{ ...hf, fontSize: size, letterSpacing: '-0.01em', color: p.charcoal }}>{value}</span>;
}

/** Links for contact details: tel:, mailto: and the website. */
export const telHref = (phone: string) => `tel:${phone.replace(/[^\d+]/g, '')}`;
export const mailHref = (email: string) => `mailto:${email}`;
export const webHref = (site: string) => (/^https?:\/\//i.test(site) ? site : `https://${site}`);

export function MiniStat({ p, hf, value, label, plain = false }: { p: Palette; hf: CSSProperties; value: string; label: string; plain?: boolean }) {
    return (
        <div>
            <div className="leading-none">{plain ? <span className="text-[22px] font-medium tabular-nums" style={{ ...hf, letterSpacing: '-0.01em' }}>{value}</span> : <Amount p={p} hf={hf} value={value} size={22} />}</div>
            <div className="mt-1.5 text-[11px]" style={{ color: p.muted }}>{label}</div>
        </div>
    );
}

/** One column of a white strip card with dividers. */
export function Step({ p, hf, title, value, note }: { p: Palette; hf: CSSProperties; title: string; value: string; note?: string }) {
    return (
        <div className="flex-1 border-t px-5 py-2 first:border-t-0 @lg:border-l @lg:border-t-0 @lg:py-0 @lg:first:border-l-0" style={{ borderColor: p.cardLine }}>
            <div className="text-[11.5px] font-medium" style={hf}>{title}</div>
            <div className="mt-1.5"><Amount p={p} hf={hf} value={value} size={20} /></div>
            {note && <div className="mt-1 text-[10.5px]" style={{ color: p.muted }}>{note}</div>}
        </div>
    );
}

export function ContactItem({ p, hf, icon: Icon = Mail, title, text, n = 0, href }: { p: Palette; hf: CSSProperties; icon?: typeof Mail; title: string; text: string; n?: number; href?: string }) {
    return (
        <div className="flex min-w-0 items-center gap-3 px-1 py-1">
            <span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full" style={badge(p, n)} aria-hidden>
                <Icon className="h-4 w-4" strokeWidth={2} />
            </span>
            <div className="min-w-0 text-[12px] leading-tight">
                <div className="font-medium" style={hf}>{title}</div>
                {href
                    ? <a href={href} className="line-clamp-2 break-words underline decoration-1 underline-offset-2" style={{ color: p.text }} target={href.startsWith('http') ? '_blank' : undefined} rel="noopener">{text}</a>
                    : <div className="line-clamp-2 break-words" style={{ color: p.muted }}>{text}</div>}
            </div>
        </div>
    );
}

export function Row({ p, label, value }: { p: Palette; label: string; value: string }) {
    return <div className="flex justify-between gap-3"><span style={{ color: p.muted }}>{label}</span><span className="tabular-nums" style={{ color: p.charcoal }}>{value}</span></div>;
}

export function Tag({ p, on, soft = false, children }: { p: Palette; on: boolean; soft?: boolean; children: ReactNode }) {
    const style: CSSProperties = on
        ? { background: soft ? 'rgb(255 255 255 / 0.25)' : p.card, color: soft ? p.onAccent : p.accentInk }
        : soft ? { background: p.bg, color: p.muted } : { background: p.accent, color: p.onAccent };
    return <span className="rounded-full px-2.5 py-0.5 text-[10.5px] font-semibold" style={style}>{children}</span>;
}

export function Prose({ p, html, className, color, align }: { p: Palette; html: string; className?: string; color?: string; align?: Align }) {
    return <div className={cn('kn-prose prose-app', className)} style={{ color: color ?? p.muted, textAlign: align }} dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(html, { ADD_ATTR: ['target'], FORBID_TAGS: ['style', 'form', 'input', 'iframe'] }) }} />;
}

export type AcceptAction = { onClick?: () => void; text?: string; disabled?: boolean; title?: string };

export function AcceptButton({ p, label, action }: { p: Palette; label: string; action?: AcceptAction }) {
    const live = !!action?.onClick && !action.disabled;
    return (
        <button type="button" disabled={!live} title={action?.title ?? (action ? undefined : 'Clients can accept once the quote is sent')} onClick={action?.onClick}
            data-testid={action ? 'accept-open' : undefined}
            className={`inline-flex items-center gap-3 rounded-full py-1.5 pl-6 pr-1.5 text-[13px] font-medium transition-transform duration-150 ${live ? 'cursor-pointer hover:-translate-y-0.5' : ''} ${action?.disabled ? 'opacity-70' : ''}`}
            style={{ background: p.accent, color: p.onAccent }}>
            {action?.text ?? `Accept ${label.toLowerCase()}`}
            <span className="flex h-8 w-8 items-center justify-center rounded-full" style={{ background: p.dark, color: p.onDark }} aria-hidden><ArrowRight className="h-4 w-4" strokeWidth={2.25} /></span>
        </button>
    );
}
