"use client";

import { useSafeIntl } from "@kopexa/i18n";
import { EditIcon } from "@kopexa/icons";
import { Button, Card, Chip, Heading, Select, Textarea } from "@kopexa/sight";
import { type CardVariantProps, impactCard } from "@kopexa/theme";
import { useState } from "react";
import { messages } from "./messages";
import {
	getScale,
	type ImpactLevel,
	type ImpactScaleConfig,
	type ImpactScalePreset,
	impactLevels,
} from "./scales";

// ============================================
// Types (aligned with Go ImpactMixin schema)
// ============================================

export interface ImpactValue {
	/** Rating 0-5. Vertraulichkeit (Confidentiality). */
	impactConfidentiality: ImpactLevel;
	/** Rating 0-5. Integrität (Integrity). */
	impactIntegrity: ImpactLevel;
	/** Rating 0-5. Verfügbarkeit (Availability) - DORA Critical! */
	impactAvailability: ImpactLevel;
	/** Rating 0-5. Authentizität (Authenticity/Accountability). */
	impactAuthenticity?: ImpactLevel;
	/** Human-readable explanation for the chosen impact scores. Focus on the highest score. */
	impactJustification?: string;
}

// ============================================
// Impact Item Row Component
// ============================================

interface ImpactItemRowProps {
	label: string;
	shortLabel: string;
	value: ImpactLevel;
	isEditing: boolean;
	scale: ImpactScaleConfig;
	formatLabel: (level: ImpactLevel) => string;
	onLevelChange: (level: ImpactLevel) => void;
}

function ImpactItemRow({
	label,
	shortLabel,
	value,
	isEditing,
	scale,
	formatLabel,
	onLevelChange,
}: ImpactItemRowProps) {
	const config = scale[value];
	const isUnrated = value === 0;
	const percentage = isUnrated ? 0 : (value / 5) * 100;
	const styles = impactCard({ unrated: isUnrated });

	return (
		<div className={styles.row()}>
			<div className={styles.rowContent()}>
				{/* Icon */}
				<span className={styles.rowIcon()}>{shortLabel}</span>

				{/* Content */}
				<div className={styles.rowBody()}>
					<div className={styles.rowHeader()}>
						<span className={styles.rowLabel()}>{label}</span>
						{isEditing ? (
							<Select
								value={String(value)}
								onValueChange={(val) =>
									onLevelChange(Number(val) as ImpactLevel)
								}
								size="sm"
							>
								<Select.Trigger className="w-36">
									<Select.Value />
								</Select.Trigger>
								<Select.Content>
									{impactLevels.map((level) => (
										<Select.Item key={level} value={String(level)}>
											<span className="flex items-center gap-2">
												<span className="text-xs text-muted-foreground w-3">
													{level}
												</span>
												{formatLabel(level)}
											</span>
										</Select.Item>
									))}
								</Select.Content>
							</Select>
						) : (
							<div className={styles.rowValue()}>
								{!isUnrated && (
									<span className={styles.rowValueNumber()}>{value}</span>
								)}
								<span
									className={styles.rowValueBadge({
										className: isUnrated
											? undefined
											: `${config.color} ${config.bgColor}`,
									})}
								>
									{formatLabel(value)}
								</span>
							</div>
						)}
					</div>

					{/* Progress Bar */}
					{!isUnrated && !isEditing && (
						<div className={styles.progressContainer()}>
							<div
								className={styles.progressBar({ className: config.barColor })}
								style={{ width: `${percentage}%` }}
							/>
						</div>
					)}
				</div>
			</div>
		</div>
	);
}

// ============================================
// Impact Card Component
// ============================================

export interface ImpactCardProps {
	/** The impact data */
	value?: ImpactValue;
	/** Callback when the impact changes */
	onChange?: (impact: ImpactValue) => void;
	/** Show justification field */
	showJustification?: boolean;
	/** Show authenticity as 4th dimension (CIAA) */
	showAuthenticity?: boolean;
	/** Make the component read-only */
	readOnly?: boolean;
	/** Scale preset or custom scale config */
	scale?: ImpactScalePreset | ImpactScaleConfig;
	/** Custom title for the card */
	title?: string;
	/**
	 * Display variant:
	 * - `card`: Wrapped in a Card with edit/save/cancel buttons (default)
	 * - `inline`: No card wrapper, always editable, changes propagate immediately
	 */
	variant?: "card" | "inline";
	/** Show attention indicator when impact values need to be filled */
	needsAttention?: boolean;
	/** Props forwarded to the underlying `Card.Root` (e.g. `spacing`, `shadow`, `radius`). Only applies when `variant="card"`. */
	cardProps?: CardVariantProps;
	/** Size of the edit icon button. Only applies when `variant="card"`. */
	editButtonSize?: "sm" | "md" | "lg";
}

const defaultImpact: ImpactValue = {
	impactConfidentiality: 0,
	impactIntegrity: 0,
	impactAvailability: 0,
	impactAuthenticity: 0,
};

export function ImpactCard({
	value,
	onChange,
	showJustification = false,
	showAuthenticity = false,
	readOnly = false,
	scale = "risk",
	title,
	variant = "card",
	needsAttention = false,
	cardProps,
	editButtonSize = "sm",
}: ImpactCardProps) {
	const intl = useSafeIntl();
	const isInline = variant === "inline";
	const [isEditing, setIsEditing] = useState(false);
	const [editValues, setEditValues] = useState<ImpactValue>(
		value || defaultImpact,
	);

	// For inline variant, always show as editing (form mode)
	const effectiveIsEditing = isInline ? !readOnly : isEditing;

	const styles = impactCard({ editing: !isInline && isEditing });

	// Resolve scale config
	const scaleConfig: ImpactScaleConfig =
		typeof scale === "string" ? getScale(scale) : scale;

	// i18n helper for scale labels
	const formatLabel = (level: ImpactLevel): string => {
		const config = scaleConfig[level];
		return intl.formatMessage(config.message);
	};

	// i18n labels
	const t = {
		titleCia: intl.formatMessage(messages.title_cia),
		titleCiaa: intl.formatMessage(messages.title_ciaa),
		confidentiality: intl.formatMessage(messages.confidentiality),
		integrity: intl.formatMessage(messages.integrity),
		availability: intl.formatMessage(messages.availability),
		authenticity: intl.formatMessage(messages.authenticity),
		justification: intl.formatMessage(messages.justification),
		justificationPlaceholder: intl.formatMessage(
			messages.justification_placeholder,
		),
		noJustification: intl.formatMessage(messages.no_justification),
		edit: intl.formatMessage(messages.edit),
		cancel: intl.formatMessage(messages.cancel),
		save: intl.formatMessage(messages.save),
		required: intl.formatMessage(messages.required),
	};

	// Derive default title based on authenticity
	const defaultTitle = showAuthenticity ? t.titleCiaa : t.titleCia;
	const cardTitle = title ?? defaultTitle;

	const handleSave = () => {
		onChange?.(editValues);
		setIsEditing(false);
	};

	const handleCancel = () => {
		setEditValues(value || defaultImpact);
		setIsEditing(false);
	};

	const handleStartEdit = () => {
		setEditValues(value || defaultImpact);
		setIsEditing(true);
	};

	// In inline mode, always use value; in card mode, use editValues when editing
	const currentImpact = isInline
		? value || defaultImpact
		: isEditing
			? editValues
			: value || defaultImpact;

	const handleLevelChange =
		(
			key:
				| "impactConfidentiality"
				| "impactIntegrity"
				| "impactAvailability"
				| "impactAuthenticity",
		) =>
		(level: ImpactLevel) => {
			const newValues = {
				...(isInline ? value || defaultImpact : editValues),
				[key]: level,
			};
			if (isInline) {
				// Inline mode: propagate changes immediately
				onChange?.(newValues);
			} else {
				setEditValues(newValues);
			}
		};

	const handleJustificationChange = (justification: string) => {
		const newValues = {
			...(isInline ? value || defaultImpact : editValues),
			impactJustification: justification || undefined,
		};
		if (isInline) {
			// Inline mode: propagate changes immediately
			onChange?.(newValues);
		} else {
			setEditValues(newValues);
		}
	};

	// Calculate highest impact for justification hint
	const highestImpact = Math.max(
		currentImpact.impactConfidentiality,
		currentImpact.impactIntegrity,
		currentImpact.impactAvailability,
		currentImpact.impactAuthenticity ?? 0,
	) as ImpactLevel;

	const highestLabel = formatLabel(highestImpact);
	const justificationHint = intl.formatMessage(messages.justification_hint, {
		level: highestLabel,
	});

	// Shared content for both variants
	const impactRows = (
		<>
			<ImpactItemRow
				label={t.confidentiality}
				shortLabel="C"
				value={currentImpact.impactConfidentiality}
				isEditing={effectiveIsEditing}
				scale={scaleConfig}
				formatLabel={formatLabel}
				onLevelChange={handleLevelChange("impactConfidentiality")}
			/>
			<ImpactItemRow
				label={t.integrity}
				shortLabel="I"
				value={currentImpact.impactIntegrity}
				isEditing={effectiveIsEditing}
				scale={scaleConfig}
				formatLabel={formatLabel}
				onLevelChange={handleLevelChange("impactIntegrity")}
			/>
			<ImpactItemRow
				label={t.availability}
				shortLabel="A"
				value={currentImpact.impactAvailability}
				isEditing={effectiveIsEditing}
				scale={scaleConfig}
				formatLabel={formatLabel}
				onLevelChange={handleLevelChange("impactAvailability")}
			/>
			{showAuthenticity && (
				<ImpactItemRow
					label={t.authenticity}
					shortLabel="Au"
					value={currentImpact.impactAuthenticity ?? 0}
					isEditing={effectiveIsEditing}
					scale={scaleConfig}
					formatLabel={formatLabel}
					onLevelChange={handleLevelChange("impactAuthenticity")}
				/>
			)}
		</>
	);

	const justificationContent = showJustification && (
		<div className={styles.justificationSection()}>
			<label
				htmlFor="impact-justification"
				className={styles.justificationLabel()}
			>
				{t.justification}
				{highestImpact > 0 && (
					<span className={styles.justificationHint()}>
						{justificationHint}
					</span>
				)}
			</label>
			{effectiveIsEditing ? (
				<Textarea
					id="impact-justification"
					value={currentImpact.impactJustification || ""}
					onChange={(e) => handleJustificationChange(e.target.value)}
					placeholder={t.justificationPlaceholder}
					rows={3}
					className="text-sm"
				/>
			) : currentImpact.impactJustification ? (
				<p className={styles.justificationText()}>
					{currentImpact.impactJustification}
				</p>
			) : (
				<p className={styles.justificationEmpty()}>{t.noJustification}</p>
			)}
		</div>
	);

	// Inline variant: no card wrapper, always editable
	if (isInline) {
		return (
			<div className={styles.wrapper()}>
				{title && (
					<div className={styles.inlineHeader()}>
						<Heading level="h4" className="text-sm font-medium">
							{title}
						</Heading>
					</div>
				)}
				{impactRows}
				{justificationContent}
			</div>
		);
	}

	// Card variant: wrapped in Card with edit/save/cancel
	return (
		<Card.Root {...cardProps} className={styles.root()}>
			<Card.Header
				className={`flex flex-row items-center justify-between ${needsAttention ? "bg-destructive/10 rounded-t-lg" : ""}`}
			>
				<div className="flex items-center gap-2">
					<Heading level="h4" className="text-sm font-medium">
						{cardTitle}
					</Heading>
					{isEditing && (
						<Chip size="sm" color="primary">
							{t.edit}
						</Chip>
					)}
					{needsAttention && !isEditing && (
						<Chip size="sm" color="destructive" variant="solid">
							{t.required}
						</Chip>
					)}
				</div>
				{!readOnly &&
					(!isEditing ? (
						<Button
							variant="ghost"
							size={editButtonSize}
							isIconOnly
							onClick={handleStartEdit}
							aria-label={t.edit}
						>
							<EditIcon className="size-4" />
						</Button>
					) : (
						<div className="flex items-center gap-2">
							<Button variant="ghost" size="sm" onClick={handleCancel}>
								{t.cancel}
							</Button>
							<Button size="sm" onClick={handleSave}>
								{t.save}
							</Button>
						</div>
					))}
			</Card.Header>
			<Card.Body className="space-y-3">
				{impactRows}
				{justificationContent}
			</Card.Body>
		</Card.Root>
	);
}
