<script lang="ts">
	import { Target, Plus, FileOutput } from '@lucide/svelte';
	import { goto } from '$app/navigation';
	import * as Card from '$lib/components/ui/card';
	import { Button } from '$lib/components/ui/button';
	import { companyStore } from '$lib/stores/company.svelte';
	import {
		opportunitiesAPI,
		pipelinesAPI,
		stagesAPI,
		accountsAPI,
		serviceRequestsAPI,
		type Opportunity,
		type OpportunityInput,
		type Pipeline,
		type Stage,
		type Account
	} from '$lib/api/crm';
	import { formatMoney, OPERATION_TYPES, TRANSPORT_MODES } from '$lib/components/crm/format';
	import { crmCatalogs } from '$lib/stores/crm-catalogs.svelte';
	import { toast } from 'svelte-sonner';

	let pipelines = $state<Pipeline[]>([]);
	let stages = $state<Stage[]>([]);
	let opps = $state<Opportunity[]>([]);
	let accounts = $state<Account[]>([]);
	let selectedPipelineId = $state<number | null>(null);
	let loading = $state(false);
	let busy = $state(false);
	let draggingId = $state<number | null>(null);

	let modalOpen = $state(false);
	let saving = $state(false);
	let form = $state<OpportunityInput>({ name: '' });

	// Convertir oportunidad → solicitud (la dirección se hereda de la oportunidad)
	let convertOpen = $state(false);
	let converting = $state(false);
	let convertOpp = $state<Opportunity | null>(null);
	let convertForm = $state<{ operation_type: string; transport_mode?: string; incoterm?: string; origin?: string; destination?: string; notes?: string }>({ operation_type: 'exportacion' });

	// Cierre de oportunidad (ganada/perdida) con fecha y, si se pierde, motivo
	let closeOpen = $state(false);
	let closing = $state(false);
	let closeCtx = $state<{ opp: Opportunity; stageId: number; isWon: boolean } | null>(null);
	let closeForm = $state<{ date: string; reason: string }>({ date: '', reason: '' });

	const companyId = $derived(companyStore.activeCompany?.id ?? null);

	const currentStages = $derived(
		stages
			.filter((s) => s.pipeline_id === selectedPipelineId)
			.slice()
			.sort((a, b) => a.position - b.position)
	);

	function oppsForStage(stageId: number): Opportunity[] {
		return opps.filter((o) => o.stage_id === stageId);
	}

	function stageTotal(stageId: number): number {
		return oppsForStage(stageId).reduce((sum, o) => sum + Number(o.amount ?? 0), 0);
	}

	function accountName(id: number | null): string {
		return accounts.find((a) => a.id === id)?.name ?? '';
	}

	$effect(() => {
		const cid = companyId;
		if (!cid) return;
		void crmCatalogs.preload(['incoterm']);
		void load(cid);
	});

	async function load(cid: number) {
		loading = true;
		try {
			const [pl, st, ac] = await Promise.all([
				pipelinesAPI.list(cid),
				stagesAPI.list(cid),
				accountsAPI.list(cid)
			]);
			pipelines = pl;
			stages = st;
			accounts = ac;
			if (!selectedPipelineId || !pl.some((p) => p.id === selectedPipelineId)) {
				selectedPipelineId = pl.find((p) => p.is_default)?.id ?? pl[0]?.id ?? null;
			}
			opps = selectedPipelineId
				? await opportunitiesAPI.list(cid, { pipeline_id: selectedPipelineId })
				: [];
		} catch (e) {
			toast.error(e instanceof Error ? e.message : 'No se pudo cargar el pipeline');
		} finally {
			loading = false;
		}
	}

	async function onPipelineChange() {
		if (companyId) await load(companyId);
	}

	async function seedPipeline() {
		if (!companyId) return;
		busy = true;
		try {
			const p = await pipelinesAPI.create(
				{ name: 'Ventas', is_default: pipelines.length === 0 },
				companyId
			);
			const defs: [string, number, boolean, boolean][] = [
				['Propuesta', 50, false, false],
				['Negociación', 75, false, false],
				['Ganada', 100, true, false],
				['Perdida', 0, false, true]
			];
			let position = 0;
			for (const [name, probability, is_won, is_lost] of defs) {
				await stagesAPI.create(
					{ pipeline_id: p.id, name, position: position++, probability, is_won, is_lost },
					companyId
				);
			}
			selectedPipelineId = p.id;
			await load(companyId);
			toast.success('Embudo de ejemplo creado');
		} catch (e) {
			toast.error(e instanceof Error ? e.message : 'No se pudo crear el embudo');
		} finally {
			busy = false;
		}
	}

	function openCreate() {
		form = {
			name: '',
			pipeline_id: selectedPipelineId ?? undefined,
			stage_id: currentStages[0]?.id,
			operation_type: 'exportacion'
		};
		modalOpen = true;
	}

	async function save(event: SubmitEvent) {
		event.preventDefault();
		if (!companyId) return;
		if (!form.name?.trim()) {
			toast.error('El nombre es obligatorio');
			return;
		}
		saving = true;
		try {
			await opportunitiesAPI.create(
				{ ...form, pipeline_id: selectedPipelineId ?? undefined },
				companyId
			);
			toast.success('Oportunidad creada');
			modalOpen = false;
			await load(companyId);
		} catch (e) {
			toast.error(e instanceof Error ? e.message : 'No se pudo crear la oportunidad');
		} finally {
			saving = false;
		}
	}

	function openConvert(opp: Opportunity) {
		convertOpp = opp;
		convertForm = { operation_type: opp.operation_type ?? 'exportacion' };
		convertOpen = true;
	}

	async function confirmConvert() {
		if (!companyId || !convertOpp) return;
		converting = true;
		try {
			const sr = await serviceRequestsAPI.fromOpportunity(
				convertOpp.id,
				{
					operation_type: convertForm.operation_type,
					transport_mode: convertForm.transport_mode || undefined,
					incoterm: convertForm.incoterm || undefined,
					origin: convertForm.origin || undefined,
					destination: convertForm.destination || undefined,
					notes: convertForm.notes || undefined
				},
				companyId
			);
			toast.success('Solicitud creada desde la oportunidad');
			convertOpen = false;
			await goto(`/dashboard/crm/solicitudes/${sr.id}`);
		} catch (e) {
			toast.error(e instanceof Error ? e.message : 'No se pudo convertir');
		} finally {
			converting = false;
		}
	}

	function onDragStart(event: DragEvent, id: number) {
		draggingId = id;
		event.dataTransfer?.setData('text/plain', String(id));
		if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move';
	}

	async function onDrop(event: DragEvent, stageId: number) {
		event.preventDefault();
		const id = draggingId;
		draggingId = null;
		if (!id || !companyId) return;
		const opp = opps.find((o) => o.id === id);
		if (!opp || opp.stage_id === stageId) return;
		// Al mover a Ganada/Perdida, pedir fecha (y motivo si se pierde) antes de cerrar
		const stage = currentStages.find((s) => s.id === stageId);
		if (stage && (stage.is_won || stage.is_lost)) {
			closeCtx = { opp, stageId, isWon: !!stage.is_won };
			closeForm = { date: new Date().toISOString().slice(0, 10), reason: '' };
			closeOpen = true;
			return;
		}
		try {
			const updated = await opportunitiesAPI.move(id, stageId, companyId);
			opps = opps.map((o) => (o.id === id ? updated : o));
		} catch (e) {
			toast.error(e instanceof Error ? e.message : 'No se pudo mover la oportunidad');
		}
	}

	async function confirmClose() {
		if (!companyId || !closeCtx) return;
		closing = true;
		try {
			await opportunitiesAPI.move(closeCtx.opp.id, closeCtx.stageId, companyId);
			const patch = closeCtx.isWon
				? { won_date: closeForm.date || undefined }
				: { lost_date: closeForm.date || undefined, lost_reason: closeForm.reason || undefined };
			const updated = await opportunitiesAPI.update(closeCtx.opp.id, patch, companyId);
			opps = opps.map((o) => (o.id === closeCtx!.opp.id ? updated : o));
			closeOpen = false;
		} catch (e) {
			toast.error(e instanceof Error ? e.message : 'No se pudo cerrar la oportunidad');
		} finally {
			closing = false;
		}
	}
</script>

<div class="space-y-6">
	<div class="flex flex-wrap items-center justify-between gap-3">
		<div>
			<h1 class="flex items-center gap-2 text-2xl font-bold tracking-tight">
				<Target class="h-6 w-6" />
				Oportunidades
			</h1>
			<p class="mt-1 text-sm text-muted-foreground">Arrastra las tarjetas entre etapas del embudo.</p>
		</div>
		<div class="flex items-center gap-2">
			{#if pipelines.length > 1}
				<select
					class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring"
					bind:value={selectedPipelineId}
					onchange={onPipelineChange}
				>
					{#each pipelines as p (p.id)}<option value={p.id}>{p.name}</option>{/each}
				</select>
			{/if}
			<Button onclick={openCreate} disabled={!companyId || currentStages.length === 0}>
				<Plus class="mr-1 h-4 w-4" /> Nueva oportunidad
			</Button>
		</div>
	</div>

	{#if !companyId}
		<Card.Root><Card.Content class="py-8 text-center text-sm text-muted-foreground">Selecciona una compañía.</Card.Content></Card.Root>
	{:else if loading}
		<p class="text-sm text-muted-foreground">Cargando pipeline…</p>
	{:else if currentStages.length === 0}
		<Card.Root>
			<Card.Content class="flex flex-col items-center gap-3 py-10 text-center">
				<p class="text-sm text-muted-foreground">Aún no tienes un embudo con etapas.</p>
				<Button onclick={seedPipeline} disabled={busy}>
					{busy ? 'Creando…' : 'Crear embudo de ejemplo'}
				</Button>
			</Card.Content>
		</Card.Root>
	{:else}
		<div class="flex gap-4 overflow-x-auto pb-4">
			{#each currentStages as stage (stage.id)}
				<div
					class="flex w-72 shrink-0 flex-col rounded-lg border bg-muted/30"
					role="list"
					ondragover={(e) => e.preventDefault()}
					ondrop={(e) => onDrop(e, stage.id)}
				>
					<div class="flex items-center justify-between border-b px-3 py-2">
						<span class="text-sm font-semibold">{stage.name}</span>
						<span class="rounded-full bg-background px-2 py-0.5 text-xs text-muted-foreground">
							{oppsForStage(stage.id).length}
						</span>
					</div>
					<div class="px-3 py-1 text-xs text-muted-foreground">{formatMoney(stageTotal(stage.id))}</div>
					<div class="flex min-h-24 flex-1 flex-col gap-2 p-2">
						{#each oppsForStage(stage.id) as opp (opp.id)}
							<div
								class="cursor-grab rounded-md border bg-card p-3 shadow-sm active:cursor-grabbing"
								role="listitem"
								draggable="true"
								ondragstart={(e) => onDragStart(e, opp.id)}
							>
								<p class="text-sm font-medium">{opp.name}</p>
								{#if opp.reference}
									<p class="font-mono text-[11px] text-muted-foreground">{opp.reference}</p>
								{/if}
								{#if accountName(opp.account_id)}
									<p class="text-xs text-muted-foreground">{accountName(opp.account_id)}</p>
								{/if}
								<div class="mt-2 flex items-center justify-between">
									<span class="text-sm font-semibold">{formatMoney(opp.amount, opp.currency)}</span>
									{#if opp.status === 'won'}
										<span class="rounded-full bg-emerald-100 px-1.5 py-0.5 text-[10px] text-emerald-700 dark:bg-emerald-950/40 dark:text-emerald-400">Ganada</span>
									{:else if opp.status === 'lost'}
										<span class="rounded-full bg-red-100 px-1.5 py-0.5 text-[10px] text-red-700 dark:bg-red-950/40 dark:text-red-400">Perdida</span>
									{:else if opp.probability !== null}
										<span class="text-[10px] text-muted-foreground">{opp.probability}%</span>
									{/if}
								</div>
								{#if opp.won_date}
									<p class="mt-1 text-[10px] text-emerald-600 dark:text-emerald-400">Ganada: {opp.won_date}</p>
								{:else if opp.lost_date}
									<p class="mt-1 text-[10px] text-red-600 dark:text-red-400">Perdida: {opp.lost_date}{#if opp.lost_reason} — {opp.lost_reason}{/if}</p>
								{/if}
								<button type="button" class="mt-2 inline-flex items-center gap-1 text-[11px] text-primary hover:underline" onclick={() => openConvert(opp)}>
									<FileOutput class="h-3 w-3" /> Convertir a solicitud
								</button>
							</div>
						{/each}
					</div>
				</div>
			{/each}
		</div>
	{/if}
</div>

{#if modalOpen}
	<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4" role="presentation" onclick={() => (modalOpen = false)}>
		<div class="w-full max-w-lg overflow-y-auto rounded-lg border bg-card p-6 shadow-lg" role="dialog" aria-modal="true" onclick={(e) => e.stopPropagation()}>
			<h2 class="mb-4 text-lg font-semibold">Nueva oportunidad</h2>
			<form class="grid gap-4" onsubmit={save}>
				<label class="flex flex-col gap-1 text-sm">
					<span class="font-medium">Nombre *</span>
					<input class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={form.name} required />
				</label>
				<label class="flex flex-col gap-1 text-sm">
					<span class="font-medium">Cuenta</span>
					<select class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={form.account_id}>
						<option value={undefined}>— Sin cuenta —</option>
						{#each accounts as a (a.id)}<option value={a.id}>{a.name}</option>{/each}
					</select>
				</label>
				<label class="flex flex-col gap-1 text-sm">
					<span class="font-medium">Dirección de la operación</span>
					<select class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={form.operation_type}>
						{#each OPERATION_TYPES as o (o.value)}<option value={o.value}>{o.label}</option>{/each}
					</select>
					<span class="text-xs text-muted-foreground">Importación/Exportación fluye a Solicitud, Cotización y Embarque.</span>
				</label>
				<div class="grid grid-cols-2 gap-4">
					<label class="flex flex-col gap-1 text-sm">
						<span class="font-medium">Etapa</span>
						<select class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={form.stage_id}>
							{#each currentStages as s (s.id)}<option value={s.id}>{s.name}</option>{/each}
						</select>
					</label>
					<label class="flex flex-col gap-1 text-sm">
						<span class="font-medium">Monto (MXN)</span>
						<input type="number" min="0" step="0.01" class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={form.amount} />
					</label>
				</div>
				<label class="flex flex-col gap-1 text-sm">
					<span class="font-medium">Cierre estimado</span>
					<input type="date" class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={form.expected_close_date} />
				</label>
				<div class="flex justify-end gap-2">
					<Button type="button" variant="outline" onclick={() => (modalOpen = false)}>Cancelar</Button>
					<Button type="submit" disabled={saving}>{saving ? 'Guardando…' : 'Guardar'}</Button>
				</div>
			</form>
		</div>
	</div>
{/if}

{#if convertOpen && convertOpp}
	<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4" role="presentation" onclick={() => (convertOpen = false)}>
		<div class="w-full max-w-lg overflow-y-auto rounded-lg border bg-card p-6 shadow-lg" role="dialog" aria-modal="true" onclick={(e) => e.stopPropagation()}>
			<h2 class="mb-1 flex items-center gap-2 text-lg font-semibold"><FileOutput class="h-5 w-5" /> Convertir a solicitud</h2>
			<p class="mb-4 text-sm text-muted-foreground">{convertOpp.name}</p>
			<div class="grid gap-4">
				<label class="flex flex-col gap-1 text-sm">
					<span class="font-medium">Dirección de la operación</span>
					<select class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={convertForm.operation_type}>
						{#each OPERATION_TYPES as o (o.value)}<option value={o.value}>{o.label}</option>{/each}
					</select>
					{#if convertOpp.operation_type}<span class="text-xs text-muted-foreground">Heredada de la oportunidad.</span>{/if}
				</label>
				<div class="grid grid-cols-2 gap-4">
					<label class="flex flex-col gap-1 text-sm"><span class="font-medium">Medio de transporte</span>
						<select class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={convertForm.transport_mode}>
							<option value={undefined}>—</option>{#each TRANSPORT_MODES as m (m.value)}<option value={m.value}>{m.label}</option>{/each}
						</select>
					</label>
					<label class="flex flex-col gap-1 text-sm"><span class="font-medium">Incoterm</span><select class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={convertForm.incoterm}><option value={undefined}>—</option>{#each crmCatalogs.options('incoterm') as i (i.value)}<option value={i.value}>{i.label}</option>{/each}</select></label>
					<label class="flex flex-col gap-1 text-sm"><span class="font-medium">Origen</span><input class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={convertForm.origin} /></label>
					<label class="flex flex-col gap-1 text-sm"><span class="font-medium">Destino</span><input class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={convertForm.destination} /></label>
				</div>
				<label class="flex flex-col gap-1 text-sm"><span class="font-medium">Notas</span><textarea rows="2" class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={convertForm.notes}></textarea></label>
			</div>
			<div class="mt-5 flex justify-end gap-2 border-t pt-4">
				<Button variant="outline" onclick={() => (convertOpen = false)}>Cancelar</Button>
				<Button onclick={confirmConvert} disabled={converting}>{converting ? 'Convirtiendo…' : 'Convertir a solicitud'}</Button>
			</div>
		</div>
	</div>
{/if}

{#if closeOpen && closeCtx}
	<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4" role="presentation" onclick={() => (closeOpen = false)}>
		<div class="w-full max-w-md rounded-lg border bg-card p-6 shadow-lg" role="dialog" aria-modal="true" tabindex="-1" onclick={(e) => e.stopPropagation()}>
			<h2 class="mb-1 text-lg font-semibold">{closeCtx.isWon ? 'Marcar como ganada' : 'Marcar como perdida'}</h2>
			<p class="mb-4 text-sm text-muted-foreground">{closeCtx.opp.name}</p>
			<div class="grid gap-4">
				<label class="flex flex-col gap-1 text-sm">
					<span class="font-medium">{closeCtx.isWon ? 'Fecha de ganada' : 'Fecha de perdida'}</span>
					<input type="date" class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={closeForm.date} />
				</label>
				{#if !closeCtx.isWon}
					<label class="flex flex-col gap-1 text-sm">
						<span class="font-medium">Motivo de la pérdida</span>
						<textarea rows="3" class="rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" bind:value={closeForm.reason} placeholder="¿Por qué se perdió esta oportunidad?"></textarea>
					</label>
				{/if}
			</div>
			<div class="mt-5 flex justify-end gap-2 border-t pt-4">
				<Button variant="outline" onclick={() => (closeOpen = false)}>Cancelar</Button>
				<Button onclick={confirmClose} disabled={closing}>{closing ? 'Guardando…' : (closeCtx.isWon ? 'Marcar ganada' : 'Marcar perdida')}</Button>
			</div>
		</div>
	</div>
{/if}
