<script>
	import { authentication } from '../store.js';
	import { onDestroy, onMount } from 'svelte';
	import { fade } from 'svelte/transition';
	import AddStock from '../../components/AddStock.svelte';
	import { getRequest } from '../../utils/api.js';
	import { goto } from '$app/navigation';
	import { browser } from '$app/environment';

	let portfolioId = undefined;
	let result = [];
	let totalValue = 0;
	let totalAssets = 0;
	let authToken;
	let isLoading = true;
	let showModal = false;
	let searchStockResult = [];
	let orderBy;
	let currency;
	let hasChanges = false;
	let showDeleteConfirm = false;
	let stockToDelete = null;

	function handleKeyDown(event) {
		if (event.key === 'Escape' && showDeleteConfirm) {
			cancelDelete();
		}

		if (event.key === 'Escape' && showModal) {
			closeModal();
		}
	}

	onMount(() => {
		if (browser) {
			window.addEventListener('keydown', handleKeyDown);
		}

		return authentication.subscribe(async (auth) => {
			if (new Date(auth?.expirationDate) < new Date()) {
				await goto('/logout');
			}

			if (!auth || !auth.token) {
				await goto('/logout');
			} else {
				const defaultCurrency = localStorage.getItem('defaultCurrency');
				currency = defaultCurrency || 'USD';

				const defaultOrder = localStorage.getItem('defaultOrder');
				orderBy = defaultOrder || 'total';

				authToken = auth.token;
				await fetchPortfolio();
			}
		});
	});

	onDestroy(() => {
		if (browser) {
			window.removeEventListener('keydown', handleKeyDown);
		}
	});

	async function fetchPortfolio() {
		try {
			const response = await getRequest(
				`${import.meta.env.VITE_STOCKS_HOST}/api/portfolios?currency=${currency}`,
				{},
				authToken
			);

			if (response.ok) {
				await update(response.json());
			} else {
				const error = await response.json();
				console.error('Failed to find portfolio info:', error);
			}
		} catch (err) {
			console.error('Failed to find portfolio info', err);
		} finally {
			isLoading = false;
		}
	}

	async function update(response) {
		const portfolio = await response;
		if (portfolio?.length > 0) {
			if (orderBy === 'code') {
				result = portfolio[0].stocks.sort((a, b) => a.code.localeCompare(b.code));
			}

			if (orderBy === 'name') {
				result = portfolio[0].stocks.sort((a, b) => a.name.localeCompare(b.name));
			}

			if (orderBy === 'total') {
				result = portfolio[0].stocks.sort((a, b) => a.total - b.total);
			}

			if (orderBy === 'weight') {
				result = portfolio[0].stocks.sort((a, b) => b.total - a.total);
			}

			result = portfolio[0].stocks;
			totalValue = portfolio[0].totalValue;
			totalAssets = portfolio[0].totalAssets;
			portfolioId = portfolio[0].id;
		} else {
			await createNewPortfolio();
		}
	}

	async function createNewPortfolio() {
		try {
			const response = await fetch(`${import.meta.env.VITE_STOCKS_HOST}/api/portfolios`, {
				method: 'POST',
				headers: {
					Authorization: 'Bearer ' + authToken
				}
			});

			if (response.status === 400) {
				alert('Bad request. Invalid code.');
				return;
			}

			await fetchPortfolio();
		} catch (err) {
			console.error('Update failed', err);
		}
	}

	async function updatePortfolio(stocks) {
		try {
			const response = await fetch(
				`${import.meta.env.VITE_STOCKS_HOST}/api/portfolios/${portfolioId}`,
				{
					method: 'PUT',
					headers: {
						Authorization: 'Bearer ' + authToken,
						'Content-Type': 'application/json'
					},
					body: JSON.stringify({ stocks })
				}
			);

			if (response.status === 400) {
				alert('Bad request. Invalid code.');
				return;
			}

			await fetchPortfolio();
		} catch (err) {
			console.error('Update failed', err);
		}
	}

	async function searchStock(code) {
		if (!code) return;

		try {
			const res = await fetch(`${import.meta.env.VITE_STOCKS_HOST}/api/stocks?q=${code}`);
			return await res.json();
		} catch (err) {
			console.error('Search error:', err);
			return [];
		}
	}

	async function addSelectedStock(newStock) {
		const exists = result.some((stock) => stock.code === newStock.code);
		if (exists) return;

		result = [
			...result,
			{
				code: newStock.code,
				name: newStock.name,
				quantity: 0,
				price: newStock.price,
				total: 0,
				totalPercent: 0
			}
		];

		closeModal();

		await updatePortfolio(result);
	}

	async function applyChanges() {
		try {
			await updatePortfolio(result);
			hasChanges = false;
		} catch (err) {
			console.error('Update failed', err);
		}
	}

	function remove(code) {
		result = result.filter((stock) => stock.code !== code);
		updatePortfolio(result);
	}

	function formatCurrency(value) {
		return value.toLocaleString('en-US', {
			style: 'currency',
			currency: currency
		});
	}

	function calculatePercentage(part, total) {
		return total ? Math.floor((part / total) * 10000) / 100 : 0;
	}

	function updateStockQuantity(e) {
		e.preventDefault();
		const form = new FormData(e.target);
		const code = form.get('code');
		const quantity = parseInt(form.get('quantity')) || 0;

		result = result.map((stock) => (stock.code === code ? { ...stock, quantity } : stock));

		updatePortfolio(result);
	}

	function openModal() {
		searchStockResult = [];
		showModal = true;
	}

	function closeModal() {
		searchStockResult = [];
		showModal = false;
	}

	function updateOrderBy(event) {
		orderBy = event.target.value;
		fetchPortfolio();
	}

	function updateCurrency(event) {
		currency = event.target.value;
		fetchPortfolio();
	}

	function formatCode(code) {
		return code.includes(':') ? code.split(':')[1] : code;
	}

	function getFlag(code) {
		const market = code.includes(':') ? code.split(':')[0].toUpperCase() : code.toUpperCase();

		const country = {
			BVMF: 'br',
			FRA: 'de',
			ETR: 'eu'
		};

		return country[market] || 'us';
	}

	function confirmDelete(code) {
		stockToDelete = code;
		showDeleteConfirm = true;
	}

	function cancelDelete() {
		stockToDelete = null;
		showDeleteConfirm = false;
	}

	function confirmDeleteAction() {
		if (stockToDelete) {
			remove(stockToDelete);
			stockToDelete = null;
		}
		showDeleteConfirm = false;
	}

	function handleInputChange(event) {
		const form = new FormData(event.target.closest('form'));
		const code = form.get('code');
		const quantity = parseInt(form.get('quantity')) || 0;

		result = result.map((stock) => (stock.code === code ? { ...stock, quantity } : stock));
		hasChanges = true;
	}

	function openStock(code) {
		goto(`/stocks/${code}`);
	}
</script>

<svelte:head>
	<title>Portfolio</title>
	<meta name="description" content="Portfolio" />
</svelte:head>

{#if isLoading}
	<div in:fade class="flex justify-center items-center py-10">
		<svg
			class="animate-spin h-8 w-8 text-blue-500 dark:text-blue-300"
			xmlns="http://www.w3.org/2000/svg"
			fill="none"
			viewBox="0 0 24 24"
		>
			<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"
			></circle>
			<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z"></path>
		</svg>
	</div>
{:else if portfolioId}
	<div class="flex flex-wrap gap-4 mb-6 items-center">
		<button
			class="bg-blue-500 hover:bg-blue-600 text-white text-sm font-medium px-4 py-2 rounded-lg shadow"
			on:click={openModal}
		>
			Add
		</button>

		<select
			class="w-40 px-3 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-400"
			on:change={updateCurrency}
			bind:value={currency}
		>
			<option value="BRL">BRL</option>
			<option value="EUR">EUR</option>
			<option value="USD">USD</option>
		</select>

		<select
			class="w-52 px-3 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-400"
			on:change={updateOrderBy}
			bind:value={orderBy}
		>
			<option value="code">Order by Code</option>
			<option value="name">Order by Name</option>
			<option value="total">Order by Total</option>
			<option value="weight">Order by Weight</option>
		</select>
	</div>

	<AddStock
		show={showModal}
		onClose={closeModal}
		onSearch={async (code) => {
			const data = await searchStock(code);
			if (!data || data.length === 0) {
				alert('Stock not found.');
				return;
			}
			searchStockResult = data;
			const alreadyInPortfolio = result.some((s) => s.code === data[0]?.code);
			if (data.length === 1 && !alreadyInPortfolio) {
				await addSelectedStock(data[0]);
				closeModal();
			}
		}}
		onAddStock={async (stock) => {
			await addSelectedStock(stock);
			closeModal();
		}}
		searchResults={searchStockResult}
	/>

	{#if showDeleteConfirm}
		<div
			class="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white dark:bg-gray-800 p-6 rounded-xl shadow-lg z-50 text-center"
		>
			<div class="flex justify-center gap-4">
				<button
					class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg"
					on:click={confirmDeleteAction}>Confirm deletion</button
				>
				<button
					class="bg-gray-300 hover:bg-gray-400 text-gray-800 px-4 py-2 rounded-lg"
					on:click={cancelDelete}>Cancel</button
				>
			</div>
		</div>
	{/if}

	<div in:fade class="overflow-x-auto mt-6 rounded-xl shadow">
		<table class="min-w-full bg-white dark:bg-gray-900 text-sm">
			<thead class="bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200">
				<tr>
					<th class="px-4 py-3 text-left font-semibold">Total Value</th>
					<th class="px-4 py-3 text-left font-semibold">Total Assets</th>
				</tr>
			</thead>
			<tbody>
				<tr class="border-t border-gray-200 dark:border-gray-700">
					<td class="px-4 py-3 font-semibold text-gray-800 dark:text-gray-100"
						>{formatCurrency(totalValue)}</td
					>
					<td class="px-4 py-3 font-semibold text-gray-800 dark:text-gray-100">{totalAssets}</td>
				</tr>
			</tbody>
		</table>
	</div>

	<div in:fade class="overflow-x-auto mt-6 rounded-xl shadow">
		<table class="min-w-full bg-white dark:bg-gray-900 text-sm">
			<thead class="bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200">
				<tr>
					<th class="px-4 py-3">Code</th>
					<th class="px-4 py-3">Name</th>
					<th class="px-4 py-3">Qty</th>
					<th class="px-4 py-3">Price</th>
					<th class="px-4 py-3">Total</th>
					<th class="px-4 py-3">% of Portfolio</th>
					<th class="px-4 py-3"></th>
				</tr>
			</thead>
			<tbody>
				{#each result as stock}
					<tr
						class="odd:bg-gray-50 even:bg-gray-100 dark:odd:bg-gray-800 dark:even:bg-gray-700 hover:bg-blue-50 dark:hover:bg-blue-900 transition"
					>
						<td
							class="px-4 py-2 font-mono font-semibold text-blue-700 dark:text-blue-300 cursor-pointer"
							title={stock.code}
							on:click={() => openStock(stock.code)}
						>
							<div class="inline-flex items-center gap-2">
								<img
									src={`https://flagcdn.com/w40/${getFlag(stock.code)}.png`}
									alt="{getFlag(stock.code)} flag"
									class="w-5 h-auto"
								/>
								{formatCode(stock.code)}
							</div>
						</td>
						<td class="px-4 py-2 text-gray-700 dark:text-gray-300">{stock.name}</td>
						<td class="px-4 py-2">
							<form
								id="updateQuantity"
								on:submit|preventDefault={updateStockQuantity}
								class="flex items-center"
							>
								<input type="hidden" name="code" value={stock.code} />
								<input
									type="number"
									name="quantity"
									min="0"
									value={stock.quantity}
									class="w-16 px-2 py-1 text-right border rounded-lg text-sm text-gray-800 dark:text-gray-100 bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-300"
									on:input={handleInputChange}
								/>
							</form>
						</td>
						<td class="px-4 py-2 font-semibold text-green-600 dark:text-green-400"
							>{formatCurrency(stock.price)}</td
						>
						<td class="px-4 py-2 font-semibold text-gray-800 dark:text-gray-200"
							>{formatCurrency(stock.total)}</td
						>
						<td class="px-4 py-2 text-blue-600 dark:text-blue-400"
							>{calculatePercentage(stock.total, totalValue)}%</td
						>
						<td class="px-4 py-2 text-right">
							<button
								on:click={() => confirmDelete(stock.code)}
								class="inline-flex items-center justify-center p-2 rounded-full text-red-600 hover:text-white hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-400 transition"
								aria-label="Delete stock"
								title="Delete"
							>
								<svg
									xmlns="http://www.w3.org/2000/svg"
									fill="none"
									viewBox="0 0 24 24"
									stroke="currentColor"
									stroke-width="2"
									class="w-5 h-5"
								>
									<polyline points="3 6 5 6 21 6"></polyline>
									<path d="M19 6l-1 14H6L5 6"></path>
									<path d="M10 11v6"></path>
									<path d="M14 11v6"></path>
									<path d="M9 6V4h6v2"></path>
								</svg>
							</button>
						</td>
					</tr>
				{/each}
			</tbody>
		</table>
	</div>

	{#if hasChanges}
		<button
			class="fixed bottom-5 right-5 bg-blue-500 hover:bg-blue-600 text-white px-6 py-3 rounded-lg shadow-lg z-50"
			on:click={applyChanges}
		>
			Apply Changes
		</button>
	{/if}
{:else}
	<div class="text-gray-500 dark:text-gray-300 text-center py-6">No portfolio data available.</div>
{/if}
