import { useState } from 'react'
import { CircleCheck, Landmark, Loader2, Pencil, Plus } from 'lucide-react'
import { Link } from 'react-router'
import { toast } from 'sonner'
import { FormError } from '@/components/form-field'
import { paths } from '@/components/layout/nav-items'
import { MoneyInput } from '@/components/money-input'
import { Button } from '@/components/ui/button'
import { findInstallmentItem, usePeriodDebt, useSetOpeningDebt } from '@/lib/debt'
import { formatDate, formatMoney, formatNumber, parseMoney } from '@/lib/format'
import { useCreatePlanItem } from '@/lib/periods'
import { t } from '@/lib/strings'
import { cn } from '@/lib/utils'
import type { Period } from '@/types/Period'
import type { PeriodDebt } from '@/types/PeriodDebt'
import type { PlanItem } from '@/types/PlanItem'
const s = t.debt.period
/**
* Aylık plan: bu ayın banka borcu (docs/BORC_TAKIBI.md §3). Ay başı borç son ölçümden
* (elle düzeltilebilir), devreden, borç ödemesi (= birikim hedefi), taksit yükü, hedef ay sonu.
* Borç takibinde hiç veri yoksa görünmez.
*/
export function PeriodDebtSection({
period,
items,
writable,
}: {
period: Period
items: PlanItem[]
writable: boolean
}) {
const q = usePeriodDebt(period.id)
const d = q.data
if (!d || (d.opening_total === null && d.installment_load === 0)) return null
return (
{s.title}
{s.toDebt}
{s.hint}
{writable && (
)}
)
}
function Tile({
label,
amount,
sign,
hint,
}: {
label: string
amount: number | null
sign?: string
hint?: string
}) {
return (
{sign && {sign} }
{label}
{amount === null ? '—' : formatMoney(amount)}
{hint &&
{hint}
}
)
}
/** Ay başı borç: kaynağı yazılı; düzeltilebilir (dönem açıkken) */
function Opening({ period, d, writable }: { period: Period; d: PeriodDebt; writable: boolean }) {
const set = useSetOpeningDebt(period.id)
const [editing, setEditing] = useState(false)
const [value, setValue] = useState('')
const [error, setError] = useState()
const source =
d.opening_source === 'manual'
? s.manual
: d.opening_date
? s.fromSnapshot(formatDate(d.opening_date))
: s.noOpening
async function save(amount: number | null) {
setError(undefined)
try {
await set.mutateAsync(amount)
setEditing(false)
toast.success(s.openingSaved)
} catch (e) {
setError(e instanceof Error ? e.message : String(e))
}
}
return (
{s.opening}
{writable && !editing && (
)}
{editing ? (
{d.opening_source === 'manual' && (
)}
) : (
<>
{d.opening_total === null ? '—' : formatMoney(d.opening_total)}
{source}
>
)}
)
}
/** Hedef ay sonu borç (+ yol haritasıyla karşılaştırma) */
function Target({ d }: { d: PeriodDebt }) {
const diff =
d.closing_target !== null && d.roadmap_target !== null
? d.closing_target - d.roadmap_target
: null
return (
=
{s.target}
{d.closing_target === null ? '—' : formatMoney(d.closing_target)}
{d.roadmap_target !== null && (
{s.roadmap(formatMoney(d.roadmap_target))}
{diff !== null && diff !== 0 && (
0 ? 'text-expense' : 'text-income'}>
{' · '}
{diff > 0
? s.vsRoadmapAbove(formatMoney(diff))
: s.vsRoadmapBelow(formatMoney(-diff))}
)}
)}
)
}
/** Aylık başarı: ay başı − son ölçüm ≥ borç ödemesi + taksit */
function Progress({ d }: { d: PeriodDebt }) {
if (d.opening_total === null || d.latest_total === null || !d.latest_date) return null
const down = d.opening_total - d.latest_total
const needed = d.payment + d.installment_load
const ok = down >= needed && needed > 0
const ratio = needed > 0 ? Math.min(Math.max(down / needed, 0), 1) : 0
return (
{s.progressTitle(formatDate(d.latest_date))}
{ok && }
{down >= 0 ? s.paidDown(formatMoney(down)) : s.grew(formatMoney(-down))}
{' '}
· {s.needed(formatMoney(needed))}
)
}
/** Taksit yükü planda "Taksitler" sabit gideri olarak yoksa: tek tıkla ekle */
function InstallmentsSuggestion({
period,
items,
load,
}: {
period: Period
items: PlanItem[]
load: number
}) {
const create = useCreatePlanItem(period.id)
if (load <= 0) return null
const existing = findInstallmentItem(items)
if (existing) {
if (existing.amount === load) return null
return (
{s.installmentsMismatch(formatMoney(existing.amount), formatMoney(load))}
)
}
return (
)
}