<script lang="ts">
	import { Receipt, ShieldCheck, Upload, Trash2, AlertTriangle } from '@lucide/svelte';
	import * as Card from '$lib/components/ui/card';
	import { Button } from '$lib/components/ui/button';
	import { companyStore } from '$lib/stores/company.svelte';
	import { authStore, userHasPermission } from '$lib/auth';
	import {
		issuerAPI,
		satCatalogsAPI,
		RFC_REGEX,
		type IssuerSettings,
		type IssuerSettingsInput,
		type SatTaxRegime
	} from '$lib/api/fin';
	import { toast } from 'svelte-sonner';

	let form = $state<IssuerSettingsInput>({
		legal_name: '',
		rfc: '',
		tax_regime_id: 0,
		zip_code: ''
	});
	let taxRegimes = $state<SatTaxRegime[]>([]);
	let loading = $state(false);
	let saving = $state(false);
	/** true mientras la empresa no tenga datos capturados (el GET respondió 404). */
	let isNew = $state(true);
	let rfcError = $state('');
	/** Estado del CSD cargado; null mientras no haya datos fiscales. */
	let issuer = $state<IssuerSettings | null>(null);
	let cerFile = $state<File | null>(null);
	let keyFile = $state<File | null>(null);
	let csdPassword = $state('');
	let uploadingCsd = $state(false);

	const companyId = $derived(companyStore.activeCompany?.id ?? null);
	const canView = $derived(userHasPermission($authStore.user, 'fin.settings.view'));
	const canEdit = $derived(userHasPermission($authStore.user, 'fin.settings.edit'));

	$effect(() => {
		const cid = companyId;
		if (!cid || !canView) return;
		void load(cid);
	});

	async function load(cid: number) {
		loading = true;
		try {
			const [settings, regimes] = await Promise.all([
				issuerAPI.get(cid),
				satCatalogsAPI.taxRegimes(cid)
			]);
			taxRegimes = regimes;
			isNew = settings === null;
			issuer = settings;
			if (settings) {
				form = {
					legal_name: settings.legal_name,
					rfc: settings.rfc,
					tax_regime_id: settings.tax_regime_id,
					zip_code: settings.zip_code ?? ''
				};
			}
		} catch (e) {
			toast.error(e instanceof Error ? e.message : 'No se pudieron cargar los datos fiscales');
		} finally {
			loading = false;
		}
	}

	function normalizedRfc(): string {
		return (form.rfc ?? '').replace(/[\s-]/g, '').toUpperCase();
	}

	async function save(event: SubmitEvent) {
		event.preventDefault();
		const cid = companyId;
		if (!cid) return;

		const rfc = normalizedRfc();
		if (!RFC_REGEX.test(rfc)) {
			rfcError = 'El RFC no tiene un formato válido (ej. XAXX010101000)';
			return;
		}
		rfcError = '';
		if (!form.tax_regime_id) {
			toast.error('Selecciona el régimen fiscal');
			return;
		}

		saving = true;
		try {
			issuer = await issuerAPI.save(
				{ ...form, rfc, zip_code: form.zip_code?.trim() ? form.zip_code.trim() : null },
				cid
			);
			isNew = false;
			toast.success('Datos fiscales guardados');
		} catch (e) {
			toast.error(e instanceof Error ? e.message : 'No se pudieron guardar los datos fiscales');
		} finally {
			saving = false;
		}
	}

	async function uploadCsd(event: SubmitEvent) {
		event.preventDefault();
		const cid = companyId;
		if (!cid || !cerFile || !keyFile) return;
		uploadingCsd = true;
		try {
			issuer = await issuerAPI.uploadCsd(cerFile, keyFile, csdPassword, cid);
			// La contraseña no se conserva en la pantalla: ya está cifrada en el servidor y
			// dejarla en memoria del navegador no aporta nada.
			csdPassword = '';
			cerFile = null;
			keyFile = null;
			toast.success('Certificado cargado y verificado');
		} catch (e) {
			toast.error(e instanceof Error ? e.message : 'No se pudo cargar el certificado');
		} finally {
			uploadingCsd = false;
		}
	}

	async function removeCsd() {
		const cid = companyId;
		if (!cid) return;
		if (!window.confirm('Se quitará el certificado y la empresa dejará de poder timbrar. ¿Continuar?'))
			return;
		uploadingCsd = true;
		try {
			issuer = await issuerAPI.deleteCsd(cid);
			toast.success('Certificado retirado');
		} catch (e) {
			toast.error(e instanceof Error ? e.message : 'No se pudo quitar el certificado');
		} finally {
			uploadingCsd = false;
		}
	}

	const inputCls =
		'rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring';
</script>

<svelte:head>
	<title>Configuración de Facturación</title>
</svelte:head>

<div class="space-y-6">
	<div>
		<h1 class="flex items-center gap-2 text-2xl font-bold tracking-tight">
			<Receipt class="h-6 w-6" />
			Datos fiscales del emisor
		</h1>
		<p class="mt-1 text-sm text-muted-foreground">
			Identidad fiscal con la que la empresa emite sus comprobantes.
		</p>
	</div>

	{#if !canView}
		<Card.Root>
			<Card.Content>
				<p class="py-6 text-center text-sm text-muted-foreground">
					No tienes permiso para consultar los datos fiscales del emisor.
				</p>
			</Card.Content>
		</Card.Root>
	{:else}
		<Card.Root>
			<Card.Header>
				<Card.Title>{isNew ? 'Capturar datos fiscales' : 'Datos fiscales registrados'}</Card.Title>
				<Card.Description>
					{isNew
						? 'Esta empresa aún no tiene datos fiscales configurados.'
						: 'Actualiza la información con la que se emiten los comprobantes.'}
				</Card.Description>
			</Card.Header>
			<Card.Content>
				{#if loading}
					<p class="py-6 text-center text-sm text-muted-foreground">Cargando…</p>
				{:else}
					<form class="grid max-w-2xl gap-4 sm:grid-cols-2" onsubmit={save}>
						<label class="flex flex-col gap-1 text-sm sm:col-span-2">
							<span class="font-medium">Razón social *</span>
							<input
								class={inputCls}
								bind:value={form.legal_name}
								maxlength="255"
								required
								disabled={!canEdit}
							/>
						</label>

						<label class="flex flex-col gap-1 text-sm">
							<span class="font-medium">RFC *</span>
							<input
								class="{inputCls} font-mono uppercase"
								bind:value={form.rfc}
								maxlength="13"
								required
								disabled={!canEdit}
								oninput={() => (rfcError = '')}
							/>
							{#if rfcError}<span class="text-xs text-destructive">{rfcError}</span>{/if}
						</label>

						<label class="flex flex-col gap-1 text-sm">
							<span class="font-medium">Código postal del lugar de expedición</span>
							<input
								class={inputCls}
								bind:value={form.zip_code}
								maxlength="5"
								inputmode="numeric"
								disabled={!canEdit}
							/>
						</label>

						<label class="flex flex-col gap-1 text-sm sm:col-span-2">
							<span class="font-medium">Régimen fiscal *</span>
							<select class={inputCls} bind:value={form.tax_regime_id} required disabled={!canEdit}>
								<option value={0}>Selecciona un régimen…</option>
								{#each taxRegimes as regime (regime.id)}
									<option value={regime.id}>{regime.code} — {regime.description}</option>
								{/each}
							</select>
						</label>

						<div class="flex justify-end sm:col-span-2">
							<Button type="submit" disabled={saving || !canEdit || !companyId}>
								{saving ? 'Guardando…' : 'Guardar'}
							</Button>
						</div>
						{#if !canEdit}
							<p class="text-xs text-muted-foreground sm:col-span-2">
								Solo puedes consultar: se requiere el permiso de edición de datos fiscales.
							</p>
						{/if}
					</form>
				{/if}
			</Card.Content>
		</Card.Root>

		<!-- ===== Certificado de Sello Digital ===== -->
		<Card.Root>
			<Card.Header>
				<Card.Title class="flex items-center gap-2">
					<ShieldCheck class="h-5 w-5" /> Certificado de Sello Digital (CSD)
				</Card.Title>
				<Card.Description>
					Es lo que firma los comprobantes ante el SAT. Sin él no se puede timbrar.
				</Card.Description>
			</Card.Header>
			<Card.Content>
				{#if isNew}
					<p class="py-4 text-sm text-muted-foreground">
						Primero guarda los datos fiscales del emisor: el certificado se asocia a ellos.
					</p>
				{:else}
					{#if issuer?.has_csd}
						<div class="mb-4 rounded-md border border-emerald-200 bg-emerald-50 p-3 text-sm dark:border-emerald-900 dark:bg-emerald-950">
							<p class="flex items-center gap-2 font-medium text-emerald-900 dark:text-emerald-100">
								<ShieldCheck class="h-4 w-4" /> Certificado cargado
							</p>
							<dl class="mt-2 grid gap-x-6 gap-y-1 text-xs text-emerald-900 sm:grid-cols-2 dark:text-emerald-200">
								<div>
									<dt class="inline font-medium">No. de certificado:</dt>
									<dd class="inline font-mono">{issuer.csd_cert_number}</dd>
								</div>
								<div>
									<dt class="inline font-medium">Cargado el:</dt>
									<dd class="inline">{issuer.csd_uploaded_at}</dd>
								</div>
							</dl>
							{#if canEdit}
								<Button
									size="sm"
									variant="outline"
									class="mt-3"
									onclick={removeCsd}
									disabled={uploadingCsd}
								>
									<Trash2 class="mr-1 h-4 w-4" /> Quitar certificado
								</Button>
							{/if}
						</div>
					{/if}

					{#if canEdit}
						<form class="grid max-w-2xl gap-4 sm:grid-cols-2" onsubmit={uploadCsd}>
							<label class="flex flex-col gap-1 text-sm">
								<span class="font-medium">Certificado (.cer) *</span>
								<input
									type="file"
									accept=".cer"
									class={inputCls}
									required
									onchange={(e) => (cerFile = e.currentTarget.files?.[0] ?? null)}
								/>
							</label>

							<label class="flex flex-col gap-1 text-sm">
								<span class="font-medium">Llave privada (.key) *</span>
								<input
									type="file"
									accept=".key"
									class={inputCls}
									required
									onchange={(e) => (keyFile = e.currentTarget.files?.[0] ?? null)}
								/>
							</label>

							<label class="flex flex-col gap-1 text-sm sm:col-span-2">
								<span class="font-medium">Contraseña de la llave privada *</span>
								<input
									type="password"
									class={inputCls}
									bind:value={csdPassword}
									required
									autocomplete="off"
								/>
								<span class="text-xs text-muted-foreground">
									Se guarda cifrada y no se vuelve a mostrar. Al subir, se verifica que la llave
									corresponda al certificado antes de guardar nada.
								</span>
							</label>

							<p class="flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 p-3 text-xs text-amber-900 sm:col-span-2 dark:border-amber-900 dark:bg-amber-950 dark:text-amber-100">
								<AlertTriangle class="mt-0.5 h-4 w-4 shrink-0" />
								<span>
									Usa el <strong>CSD</strong>, no la FIEL: son certificados distintos y la FIEL no
									sirve para timbrar. Con la llave privada se puede firmar a nombre de la empresa
									ante el SAT, así que trátala como una credencial.
								</span>
							</p>

							<div class="flex justify-end sm:col-span-2">
								<Button type="submit" disabled={uploadingCsd || !cerFile || !keyFile || !companyId}>
									<Upload class="mr-1 h-4 w-4" />
									{uploadingCsd ? 'Verificando…' : issuer?.has_csd ? 'Reemplazar certificado' : 'Cargar certificado'}
								</Button>
							</div>
						</form>
					{:else if !issuer?.has_csd}
						<p class="py-4 text-sm text-muted-foreground">
							Esta empresa no tiene certificado cargado. Se requiere el permiso de edición para
							subirlo.
						</p>
					{/if}
				{/if}
			</Card.Content>
		</Card.Root>
	{/if}
</div>
