#!/usr/bin/env python3
"""ZZP Dashboard — JG Consultancy"""

import os, sqlite3, hashlib, secrets, json, time, ssl, urllib.request
from datetime import datetime, timedelta
from functools import wraps
from flask import Flask, request, session, redirect, url_for, render_template_string, flash, g, jsonify
from werkzeug.security import generate_password_hash, check_password_hash

# ── Config ──────────────────────────────────────────────────────────────────
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, 'data')
DB_PATH  = os.path.join(DATA_DIR, 'zzp.db')
os.makedirs(DATA_DIR, exist_ok=True)

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/zzp'
app.secret_key = secrets.token_hex(32)
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=8)
app.config['SESSION_COOKIE_PATH'] = '/zzp'

# Colors
C = dict(primary='#003366', accent='#3B82F6', success='#00A859', warning='#F59E0B',
         text='#1F2937', bg='#F3F4F6', white='#FFFFFF', border='#E5E7EB', danger='#EF4444')

# ── Database ────────────────────────────────────────────────────────────────
def get_db():
    if 'db' not in g:
        g.db = sqlite3.connect(DB_PATH)
        g.db.row_factory = sqlite3.Row
        g.db.execute("PRAGMA journal_mode=WAL")
    return g.db

@app.teardown_appcontext
def close_db(exc):
    db = g.pop('db', None)
    if db: db.close()

def init_db():
    conn = sqlite3.connect(DB_PATH)
    conn.row_factory = sqlite3.Row
    c = conn.cursor()
    c.executescript("""
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        username TEXT UNIQUE NOT NULL,
        password_hash TEXT NOT NULL
    );
    CREATE TABLE IF NOT EXISTS settings (
        key TEXT PRIMARY KEY,
        value TEXT
    );
    CREATE TABLE IF NOT EXISTS timesheets (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        date TEXT NOT NULL,
        client TEXT NOT NULL,
        activity TEXT NOT NULL,
        hours REAL NOT NULL,
        billable INTEGER DEFAULT 1,
        note TEXT DEFAULT '',
        created_at TEXT DEFAULT CURRENT_TIMESTAMP
    );
    CREATE TABLE IF NOT EXISTS invoices (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        invoice_number TEXT UNIQUE NOT NULL,
        client TEXT NOT NULL,
        period_year INTEGER,
        period_month INTEGER,
        invoice_date TEXT,
        due_date TEXT,
        subtotal REAL DEFAULT 0,
        btw REAL DEFAULT 0,
        total REAL DEFAULT 0,
        status TEXT DEFAULT 'Concept',
        created_at TEXT DEFAULT CURRENT_TIMESTAMP
    );
    CREATE TABLE IF NOT EXISTS invoice_lines (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        invoice_id INTEGER REFERENCES invoices(id),
        description TEXT,
        hours REAL,
        rate REAL,
        amount REAL
    );
    CREATE TABLE IF NOT EXISTS expenses (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        date TEXT NOT NULL,
        category TEXT NOT NULL,
        description TEXT,
        amount_excl REAL NOT NULL,
        btw REAL DEFAULT 0,
        total REAL NOT NULL,
        created_at TEXT DEFAULT CURRENT_TIMESTAMP
    );
    CREATE TABLE IF NOT EXISTS btw_quarters (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        year INTEGER,
        quarter INTEGER,
        status TEXT DEFAULT 'Nog doen',
        filed_at TEXT
    );
    CREATE TABLE IF NOT EXISTS travel_logs (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        date TEXT NOT NULL,
        client TEXT DEFAULT '',
        from_location TEXT DEFAULT '',
        to_location TEXT DEFAULT '',
        km REAL NOT NULL,
        rate_per_km REAL DEFAULT 0.23,
        amount REAL NOT NULL,
        transport_type TEXT DEFAULT 'Auto',
        purpose TEXT DEFAULT '',
        billable INTEGER DEFAULT 1,
        created_at TEXT DEFAULT CURRENT_TIMESTAMP
    );
    """)
    # Seed admin user
    pw_hash = generate_password_hash('Admin123!')
    c.execute("INSERT OR IGNORE INTO users (username, password_hash) VALUES (?,?)", ('admin', pw_hash))
    # Seed settings
    defaults = {
        'company_name': 'JG Consultancy',
        'company_address': '', 'company_kvk': '', 'company_btw': '', 'company_bank': '',
        'client_phoenix_metals_address': '', 'client_club_of_engineers_address': '',
        'rate_phoenix_metals': '100', 'rate_club_of_engineers': '100', 'rate_overig': '85',
        'payment_terms': '30',
        'travel_rate': '0.23', 'client_overig_address': ''
    }
    for k, v in defaults.items():
        c.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?,?)", (k, v))
    conn.commit()
    conn.close()

# ── Auth ────────────────────────────────────────────────────────────────────
def login_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        if 'user' not in session:
            return redirect(url_for('login'))
        return f(*args, **kwargs)
    return decorated

# ── Helpers ─────────────────────────────────────────────────────────────────
def get_setting(key, default=''):
    r = get_db().execute("SELECT value FROM settings WHERE key=?", (key,)).fetchone()
    return r['value'] if r else default

def set_setting(key, value):
    get_db().execute("INSERT OR REPLACE INTO settings (key, value) VALUES (?,?)", (key, value))
    get_db().commit()

def fmt_eur(v): return f"€ {v:,.2f}".replace(",","X").replace(".",",").replace("X",".")

def client_prefix(client):
    mapping = {'Phoenix Metals': 'PM', 'Club of Engineers': 'COE', 'Overig': 'OVR', 'Overhead': 'OHD'}
    return mapping.get(client, 'OVR')

def next_invoice_number(client, year=2026):
    prefix = client_prefix(client)
    r = get_db().execute(
        "SELECT invoice_number FROM invoices WHERE invoice_number LIKE ? ORDER BY id DESC LIMIT 1",
        (f"{year}-{prefix}-%",)).fetchone()
    if r:
        num = int(r['invoice_number'].split('-')[-1]) + 1
    else:
        num = 1
    return f"{year}-{prefix}-{num:03d}"

def calc_btw_reserve():
    db = get_db()
    year = datetime.now().year
    r = db.execute("SELECT COALESCE(SUM(btw),0) as total FROM invoices WHERE status != 'Betaald' AND invoice_date LIKE ?",
                   (f"{year}%",)).fetchone()
    return r['total'] if r else 0

# ── Base Layout ─────────────────────────────────────────────────────────────
LAYOUT = """
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{% block title %}ZZP Dashboard{% endblock %}</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:Calibri,Arial,sans-serif;color:#1F2937;background:#F3F4F6}
.sidebar{position:fixed;top:0;left:0;width:220px;height:100vh;background:#003366;color:#FFFFFF;padding:20px 0;display:flex;flex-direction:column;z-index:100;overflow-y:auto}
.sidebar .logo{padding:0 20px 20px;border-bottom:1px solid rgba(255,255,255,.15);font-size:16px;font-weight:700}
.sidebar .logo small{font-size:11px;font-weight:400;opacity:.7;display:block;margin-top:4px}
.sidebar nav{flex:1;padding:10px 0}
.sidebar nav a{display:block;padding:10px 20px;color:rgba(255,255,255,.75);text-decoration:none;font-size:14px;transition:.2s}
.sidebar nav a:hover,.sidebar nav a.active{background:rgba(255,255,255,.1);color:#FFFFFF}
.sidebar .logout{padding:10px 20px;border-top:1px solid rgba(255,255,255,.15)}
.sidebar .logout a{color:rgba(255,255,255,.6);text-decoration:none;font-size:13px}
.main{margin-left:220px;padding:24px;min-height:100vh}
.page-header{margin-bottom:24px}
.page-header h1{font-size:22px;color:#003366}
.card{background:#FFFFFF;border-radius:8px;box-shadow:0 1px 3px rgba(0,0,0,.08);padding:20px;margin-bottom:16px}
.card h3{font-size:14px;color:#6B7280;margin-bottom:8px;text-transform:uppercase;letter-spacing:.5px}
.card .big{font-size:28px;font-weight:700;color:#003366}
.card .big.green{color:#00A859}
.card .big.red{color:#EF4444}
.card .big.orange{color:#F59E0B}
.grid{display:grid;gap:16px}
.grid-2{grid-template-columns:1fr 1fr}
.grid-3{grid-template-columns:1fr 1fr 1fr}
.grid-4{grid-template-columns:repeat(4,1fr)}
.grid-5{grid-template-columns:repeat(5,1fr)}
@media(max-width:768px){.sidebar{display:none}.main{margin-left:0}.grid-2,.grid-3,.grid-4,.grid-5{grid-template-columns:1fr}
.mobile-header{display:flex!important}}
.mobile-header{display:none;background:#003366;color:#FFFFFF;padding:12px 16px;align-items:center;justify-content:space-between}
.mobile-header .menu-btn{background:none;border:none;color:#FFFFFF;font-size:24px;cursor:pointer}
table{width:100%;border-collapse:collapse;font-size:14px}
th{text-align:left;padding:10px 12px;background:#F3F4F6;color:#1F2937;font-weight:600;border-bottom:2px solid #E5E7EB}
td{padding:10px 12px;border-bottom:1px solid #E5E7EB}
tr:hover td{background:rgba(59,130,246,.04)}
.btn{display:inline-block;padding:8px 16px;border-radius:6px;border:none;cursor:pointer;font-size:14px;font-family:inherit;text-decoration:none;transition:.2s}
.btn-primary{background:#003366;color:#FFFFFF}.btn-primary:hover{opacity:.9}
.btn-accent{background:#3B82F6;color:#FFFFFF}.btn-accent:hover{opacity:.9}
.btn-success{background:#00A859;color:#FFFFFF}
.btn-warning{background:#F59E0B;color:#FFFFFF}
.btn-danger{background:#EF4444;color:#FFFFFF}
.btn-sm{padding:5px 10px;font-size:12px}
form .field{margin-bottom:14px}
form label{display:block;font-size:13px;font-weight:600;color:#1F2937;margin-bottom:4px}
form input,form select,form textarea{width:100%;padding:8px 10px;border:1px solid #E5E7EB;border-radius:6px;font-family:inherit;font-size:14px}
form textarea{resize:vertical;min-height:60px}
.progress-bar{background:#E5E7EB;border-radius:8px;height:20px;overflow:hidden}
.progress-bar .fill{height:100%;border-radius:8px;transition:width .4s}
.flash{padding:10px 16px;border-radius:6px;margin-bottom:16px;font-size:14px}
.flash-ok{background:#D1FAE5;color:#065F46}
.flash-err{background:#FEE2E2;color:#991B1B}
.badge{display:inline-block;padding:2px 8px;border-radius:12px;font-size:11px;font-weight:600}
.badge-green{background:#D1FAE5;color:#065F46}
.badge-yellow{background:#FEF3C7;color:#92400E}
.badge-red{background:#FEE2E2;color:#991B1B}
.badge-blue{background:#DBEAFE;color:#1E40AF}
.actions{display:flex;gap:6px}
.login-page{display:flex;align-items:center;justify-content:center;min-height:100vh;background:#003366}
.login-box{background:#FFFFFF;border-radius:12px;padding:40px;width:360px;box-shadow:0 8px 32px rgba(0,0,0,.15)}
.login-box h1{color:#003366;margin-bottom:8px;font-size:22px}
.login-box p{color:#6B7280;margin-bottom:24px;font-size:14px}
</style>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
"""

# ── Login Page ──────────────────────────────────────────────────────────────
LOGIN_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="login-page">
<div class="login-box">
  <h1>ZZP Dashboard</h1>
  <p>Log in om door te gaan</p>
  {% if error %}<div class="flash flash-err">{{ error }}</div>{% endif %}
  <form method="POST">
    <div class="field"><label>Gebruikersnaam</label><input type="text" name="username" required autofocus></div>
    <div class="field"><label>Wachtwoord</label><input type="password" name="password" required></div>
    <button class="btn btn-primary" style="width:100%%;margin-top:8px">Inloggen</button>
  </form>
</div>
</div>
{% endblock %}
""")

# ── Dashboard ───────────────────────────────────────────────────────────────
DASHBOARD_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header">
  <span style="font-weight:700">ZZP Dashboard</span>
  <button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button>
</div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}" class="active">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for(\'logout\') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header"><h1>Dashboard</h1></div>
  <div class="grid grid-4">
    <div class="card"><h3>Uren dit jaar</h3><div class="big">{{ data.total_hours|round(1) }}</div></div>
    <div class="card"><h3>Urencriterium (1.225u)</h3>
      <div class="big" style="font-size:20px">{{ data.pct|round(1) }}%%</div>
      <div class="progress-bar" style="margin-top:8px"><div class="fill" style="width:{{ [data.pct,100]|min }}%%;background:{% if data.pct >= 80 %}#00A859{% else %}#3B82F6{% endif %}"></div></div>
    </div>
    <div class="card"><h3>Openstaande facturen</h3><div class="big orange">{{ data.open_invoices }}</div></div>
    <div class="card"><h3>Winst dit jaar</h3><div class="big green">{{ fmt(data.profit) }}</div></div>
  </div>
  <div class="grid grid-2" style="margin-top:8px">
    <div class="card"><h3>Facturabel vs Overhead</h3>
      <p style="font-size:14px;margin-top:6px">🔵 Facturabel: <strong>{{ data.billable_hours|round(1) }}u</strong> &nbsp; ⚪ Overhead: <strong>{{ data.overhead_hours|round(1) }}u</strong></p>
    </div>
    <div class="card"><h3>BTW Reserve</h3><div class="big red" style="font-size:22px">{{ fmt(data.btw_reserve) }}</div></div>
  </div>
  <div class="grid grid-3" style="margin-top:8px">
    <div class="card"><h3>🚗 Reiskosten dit jaar</h3><div class="big" style="font-size:22px">{{ fmt(data.travel_total) }}</div></div>
    <div class="card"><h3>Kilometers dit jaar</h3><div class="big orange" style="font-size:22px">{{ data.travel_km|round(0) }} km</div></div>
    <div class="card"><h3>Vergoeding per km</h3><div class="big green" style="font-size:22px">€ 0,23</div></div>
  </div>
  <div class="grid grid-2" style="margin-top:8px">
    <div class="card"><h3>Laatste 5 activiteiten</h3>
      {% if data.recent %}
      <table><tr><th>Datum</th><th>Client</th><th>Uren</th></tr>
      {% for r in data.recent %}<tr><td>{{ r.date }}</td><td>{{ r.client }}</td><td>{{ r.hours }}</td></tr>{% endfor %}
      </table>{% else %}<p style="color:#999;font-size:14px;margin-top:8px">Nog geen uren geregistreerd</p>{% endif %}
    </div>
    <div class="card"><h3>⚠️ Openstaande acties</h3>
      {% if data.alerts %}
      {% for a in data.alerts %}<p style="font-size:13px;padding:4px 0;{{ a.style }}">{{ a.text }}</p>{% endfor %}
      {% else %}<p style="color:#00A859;font-size:14px;margin-top:8px">✅ Geen openstaande acties</p>{% endif %}
    </div>
  </div>
</div>
{% endblock %}
""")

# ── Timesheets ──────────────────────────────────────────────────────────────
TIMESHEETS_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header">
  <span style="font-weight:700">Urenregistratie</span>
  <button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button>
</div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}" class="active">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for(\'logout\') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header" style="display:flex;justify-content:space-between;align-items:center">
    <h1>Urenregistratie</h1>
    <a href="{{ url_for('timesheet_add') }}" class="btn btn-primary">+ Uren toevoegen</a>
  </div>
  {% if msg %}<div class="flash flash-ok">{{ msg }}</div>{% endif %}
  <div class="card">
    <div style="display:flex;gap:12px;align-items:center;margin-bottom:16px;flex-wrap:wrap">
      <label style="font-size:13px;font-weight:600">Filter:</label>
      <select id="filter_client" onchange="applyFilter()" style="padding:6px 10px;border:1px solid #E5E7EB;border-radius:6px;font-size:13px">
        <option value="">Alle opdrachtgevers</option><option value="Phoenix Metals">Phoenix Metals</option><option value="Club of Engineers">Club of Engineers</option><option value="Overhead">Overhead</option><option value="Overig">Overig</option><option value="Overhead">Overhead</option>
      </select>
      <select id="filter_month" onchange="applyFilter()" style="padding:6px 10px;border:1px solid #E5E7EB;border-radius:6px;font-size:13px">
        <option value="">Alle maanden</option>
        {% for m in months %}<option value="{{ m }}">{{ m }}</option>{% endfor %}
      </select>
      <span style="margin-left:auto;font-size:13px;color:#6B7280">Totaal getoond: <strong id="shown_total">0</strong>u</span>
    </div>
    <div style="overflow-x:auto">
    <table>
      <tr><th>Datum</th><th>Opdrachtgever</th><th>Activiteit</th><th>Uren</th><th>Facturabel</th><th>Acties</th></tr>
      {% for t in timesheets %}
      <tr data-client="{{ t.client }}" data-month="{{ t.date[:7] }}" data-hours="{{ t.hours }}">
        <td>{{ t.date }}</td><td>{{ t.client }}</td><td>{{ t.activity }}</td><td>{{ t.hours }}</td>
        <td>{% if t.billable %}<span class="badge badge-green">Ja</span>{% else %}<span class="badge badge-yellow">Nee</span>{% endif %}</td>
        <td class="actions">
          <a href="{{ url_for('timesheet_edit', tid=t.id) }}" class="btn btn-accent btn-sm">✏️</a>
          <form method="POST" action="{{ url_for('timesheet_delete', tid=t.id) }}" style="display:inline" onsubmit="return confirm('Verwijderen?')"><button class="btn btn-danger btn-sm">🗑️</button></form>
        </td>
      </tr>{% endfor %}
    </table>
    </div>
  </div>
  <div class="grid grid-3">
    <div class="card"><h3>Uren dit jaar</h3><div class="big">{{ total_hours|round(1) }}</div></div>
    <div class="card"><h3>Facturabel</h3><div class="big green">{{ billable_hours|round(1) }}</div></div>
    <div class="card"><h3>Overhead</h3><div class="big orange">{{ (total_hours - billable_hours)|round(1) }}</div></div>
  </div>
</div>
<script>
function applyFilter(){
  var c=document.getElementById('filter_client').value, m=document.getElementById('filter_month').value, tot=0;
  document.querySelectorAll('table tr[data-client]').forEach(function(r){
    var show=(!c||r.dataset.client===c)&&(!m||r.dataset.month===m);
    r.style.display=show?'':'none'; if(show) tot+=parseFloat(r.dataset.hours);
  });
  document.getElementById('shown_total').textContent=tot.toFixed(1);
}
applyFilter();
</script>
{% endblock %}
""")

TIMESHEET_FORM_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header"><span style="font-weight:700">{{ 'Uren bewerken' if edit else 'Uren toevoegen' }}</span><button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button></div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}" class="active">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for(\'logout\') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header"><h1>{{ 'Uren bewerken' if edit else 'Uren toevoegen' }}</h1></div>
  {% if error %}<div class="flash flash-err">{{ error }}</div>{% endif %}
  <div class="card" style="max-width:500px">
    <form method="POST">
      <div class="field"><label>Datum</label><input type="date" name="date" value="{{ ts.date or today }}" required></div>
      <div class="field"><label>Opdrachtgever</label><select name="client">
        <option value="Phoenix Metals" {{ 'selected' if ts.client=='Phoenix Metals' }}>Phoenix Metals</option>
        <option value="Club of Engineers" {{ 'selected' if ts.client=='Club of Engineers' }}>Club of Engineers</option>
        <option value="Overig" {{ 'selected' if ts.client=='Overig' or not ts.client }}>Overig</option>
        <option value="Overhead" {{ 'selected' if ts.client=='Overhead' }}>Overhead</option>
      </select></div>
      <div class="field"><label>Activiteit</label><input type="text" name="activity" value="{{ ts.activity or '' }}" required></div>
      <div class="field"><label>Uren</label><input type="number" name="hours" step="0.25" min="0.25" value="{{ ts.hours or '' }}" required></div>
      <div class="field"><label>Facturabel</label><select name="billable">
        <option value="1" {{ 'selected' if ts.billable!=0 }}>Ja</option>
        <option value="0" {{ 'selected' if ts.billable==0 and edit }}>Nee</option>
      </select></div>
      <div class="field"><label>Opmerking</label><textarea name="note">{{ ts.note or '' }}</textarea></div>
      <button class="btn btn-primary">{{ 'Opslaan' if edit else 'Toevoegen' }}</button>
      <a href="{{ url_for('timesheets') }}" class="btn" style="background:#E5E7EB;color:#1F2937;margin-left:8px">Annuleren</a>
    </form>
  </div>
</div>
{% endblock %}
""")

# ── Invoices ────────────────────────────────────────────────────────────────
INVOICES_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header"><span style="font-weight:700">Facturatie</span><button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button></div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}" class="active">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for(\'logout\') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header" style="display:flex;justify-content:space-between;align-items:center">
    <h1>Facturatie</h1>
    <a href="{{ url_for('invoice_generate') }}" class="btn btn-primary">+ Factuur genereren</a>
  </div>
  {% if msg %}<div class="flash flash-ok">{{ msg }}</div>{% endif %}
  <div class="card" style="overflow-x:auto">
    <table>
      <tr><th>Factuurnummer</th><th>Opdrachtgever</th><th>Periode</th><th>Subtotaal</th><th>BTW</th><th>Totaal</th><th>Status</th><th>Acties</th></tr>
      {% for inv in invoices %}
      <tr>
        <td><strong>{{ inv.invoice_number }}</strong></td><td>{{ inv.client }}</td>
        <td>{{ inv.period_year }}-{{ '%02d' % inv.period_month }}</td>
        <td>{{ fmt(inv.subtotal) }}</td><td>{{ fmt(inv.btw) }}</td><td>{{ fmt(inv.total) }}</td>
        <td>
          <form method="POST" action="{{ url_for('invoice_status', iid=inv.id) }}" style="display:inline">
            <select name="status" onchange="this.form.submit()" style="font-size:12px;padding:3px 6px;border-radius:4px;
              {% if inv.status=='Betaald' %}color:#00A859;border-color:#00A859
              {% elif inv.status=='Over tijdig' %}color:#EF4444;border-color:#EF4444
              {% elif inv.status=='Verstuurd' %}color:#3B82F6;border-color:#3B82F6
              {% else %}color:#1F2937{% endif %}">
              {% for s in ['Concept','Verstuurd','Betaald','Over tijdig'] %}
              <option value="{{ s }}" {{ 'selected' if inv.status==s }}>{{ s }}</option>
              {% endfor %}
            </select>
          </form>
        </td>
        <td class="actions">
          <a href="{{ url_for('invoice_view', iid=inv.id) }}" class="btn btn-accent btn-sm">👁️</a>
          <form method="POST" action="{{ url_for('invoice_delete', iid=inv.id) }}" style="display:inline" onsubmit="return confirm('Factuur verwijderen?')"><button class="btn btn-danger btn-sm">🗑️</button></form>
        </td>
      </tr>{% endfor %}
    </table>
  </div>
  <div class="grid grid-3" style="margin-top:8px">
    <div class="card"><h3>Totaal gefactureerd</h3><div class="big">{{ fmt(total_invoiced) }}</div></div>
    <div class="card"><h3>Betaald</h3><div class="big green">{{ fmt(total_paid) }}</div></div>
    <div class="card"><h3>Openstaand</h3><div class="big orange">{{ fmt(total_open) }}</div></div>
  </div>
</div>
{% endblock %}
""")

INVOICE_GENERATE_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header"><span style="font-weight:700">Factuur genereren</span><button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button></div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}" class="active">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for(\'logout\') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header"><h1>Factuur genereren</h1></div>
  {% if error %}<div class="flash flash-err">{{ error }}</div>{% endif %}
  <div class="card" style="max-width:500px">
    <form method="POST">
      <div class="field"><label>Opdrachtgever</label><select name="client">
        <option value="Phoenix Metals">Phoenix Metals</option>
        <option value="Club of Engineers">Club of Engineers</option><option value="Overhead">Overhead</option>
        <option value="Overig">Overig</option><option value="Overhead">Overhead</option>
      </select></div>
      <div class="field"><label>Jaar</label><input type="number" name="year" value="{{ year }}" min="2020" max="2030"></div>
      <div class="field"><label>Maand</label><select name="month">
        {% for i in range(1,13) %}<option value="{{ i }}" {{ 'selected' if i==month }}>{{ i }}</option>{% endfor %}
      </select></div>
      <div class="field"><label>Factuurdatum</label><input type="date" name="invoice_date" value="{{ today }}"></div>
      <button class="btn btn-primary">Genereer factuur</button>
      <a href="{{ url_for('invoices') }}" class="btn" style="background:#E5E7EB;color:#1F2937;margin-left:8px">Annuleren</a>
    </form>
  </div>
  {% if preview %}
  <div class="card" style="margin-top:16px">
    <h3>Preview: {{ preview.client }} — {{ preview.year }}-{{ '%02d' % preview.month }}</h3>
    <p style="margin-top:8px;font-size:14px">{{ preview.count }} urenposten, {{ preview.total_hours|round(1) }} uur, subtotaal {{ fmt(preview.subtotal) }}</p>
  </div>
  {% endif %}
</div>
{% endblock %}
""")

INVOICE_VIEW_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header"><span style="font-weight:700">Factuur {{ inv.invoice_number }}</span><button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button></div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}" class="active">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for(\'logout\') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header" style="display:flex;justify-content:space-between;align-items:center">
    <h1>Factuur {{ inv.invoice_number }}</h1>
    <a href="{{ url_for('invoices') }}" class="btn" style="background:#E5E7EB;color:#1F2937">← Terug</a>
  </div>
  <div class="card" id="invoice-print">
    <div style="display:flex;justify-content:space-between;margin-bottom:24px">
      <div><strong style="font-size:18px;color:#003366">{{ company_name }}</strong><br>{{ company_address }}<br>KvK: {{ company_kvk }}<br>BTW: {{ company_btw }}</div>
      <div style="text-align:right"><strong style="font-size:20px">FACTUUR</strong><br>{{ inv.invoice_number }}<br>{{ inv.invoice_date }}<br><br>Status: <strong>{{ inv.status }}</strong></div>
    </div>
    <div style="margin-bottom:24px;padding:12px;background:#F3F4F6;border-radius:6px">
      <strong>Opdrachtgever:</strong><br>{{ inv.client }}<br>{{ client_address }}
    </div>
    <table>
      <tr><th>Omschrijving</th><th style="text-align:right">Uren</th><th style="text-align:right">Tarief</th><th style="text-align:right">Bedrag</th></tr>
      {% for line in lines %}
      <tr><td>{{ line.description }}</td><td style="text-align:right">{{ line.hours }}</td><td style="text-align:right">{{ fmt(line.rate) }}</td><td style="text-align:right">{{ fmt(line.amount) }}</td></tr>
      {% endfor %}
      <tr><td colspan="3" style="text-align:right;font-weight:600">Subtotaal</td><td style="text-align:right;font-weight:600">{{ fmt(inv.subtotal) }}</td></tr>
      <tr><td colspan="3" style="text-align:right">BTW 21%%</td><td style="text-align:right">{{ fmt(inv.btw) }}</td></tr>
      <tr><td colspan="3" style="text-align:right;font-weight:700;font-size:16px">Totaal</td><td style="text-align:right;font-weight:700;font-size:16px;color:#003366">{{ fmt(inv.total) }}</td></tr>
    </table>
    <div style="margin-top:24px;padding:12px;background:#F3F4F6;border-radius:6px;font-size:13px">
      <strong>Betalingsvoorwaarden:</strong> {{ payment_terms }} dagen<br>
      <strong>Bank:</strong> {{ company_bank }}<br>
      <strong>Vervaldatum:</strong> {{ inv.due_date }}
    </div>
  </div>
  <button class="btn btn-primary" onclick="window.print()">🖨️ Afdrukken</button>
</div>
{% endblock %}
""")

# ── Expenses ────────────────────────────────────────────────────────────────
EXPENSES_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header"><span style="font-weight:700">Kosten</span><button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button></div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}" class="active">💰 Kosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for(\'logout\') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header" style="display:flex;justify-content:space-between;align-items:center">
    <h1>Kosten</h1>
    <a href="{{ url_for('expense_add') }}" class="btn btn-primary">+ Kosten toevoegen</a>
  </div>
  {% if msg %}<div class="flash flash-ok">{{ msg }}</div>{% endif %}
  <div class="card" style="overflow-x:auto">
    <table>
      <tr><th>Datum</th><th>Categorie</th><th>Omschrijving</th><th>Excl. BTW</th><th>BTW</th><th>Totaal</th><th>Acties</th></tr>
      {% for e in expenses %}
      <tr>
        <td>{{ e.date }}</td><td>{{ e.category }}</td><td>{{ e.description or '' }}</td>
        <td>{{ fmt(e.amount_excl) }}</td><td>{{ fmt(e.btw) }}</td><td>{{ fmt(e.total) }}</td>
        <td class="actions">
          <a href="{{ url_for('expense_edit', eid=e.id) }}" class="btn btn-accent btn-sm">✏️</a>
          <form method="POST" action="{{ url_for('expense_delete', eid=e.id) }}" style="display:inline" onsubmit="return confirm('Verwijderen?')"><button class="btn btn-danger btn-sm">🗑️</button></form>
        </td>
      </tr>{% endfor %}
    </table>
  </div>
  <div class="grid grid-3" style="margin-top:8px">
    <div class="card"><h3>Kosten dit jaar</h3><div class="big red">{{ fmt(total_expenses) }}</div></div>
    <div class="card"><h3>BTW op kosten</h3><div class="big orange">{{ fmt(total_btw) }}</div></div>
    <div class="card"><h3>Netto kosten</h3><div class="big">{{ fmt(total_expenses - total_btw) }}</div></div>
  </div>
  <div class="card" style="margin-top:8px">
    <h3>Jaaroverzicht {{ year }}</h3>
    <table>
      <tr><th>Maand</th><th>Omzet</th><th>Kosten</th><th>Winst</th></tr>
      {% for m in monthly %}
      <tr><td>{{ m.label }}</td><td>{{ fmt(m.revenue) }}</td><td>{{ fmt(m.expenses) }}</td><td style="color:{% if m.profit >= 0 %}#00A859{% else %}#EF4444{% endif %};font-weight:600">{{ fmt(m.profit) }}</td></tr>
      {% endfor %}
    </table>
  </div>
</div>
{% endblock %}
""")

EXPENSE_FORM_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header"><span style="font-weight:700">{{ 'Kosten bewerken' if edit else 'Kosten toevoegen' }}</span><button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button></div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}" class="active">💰 Kosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for(\'logout\') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header"><h1>{{ 'Kosten bewerken' if edit else 'Kosten toevoegen' }}</h1></div>
  {% if error %}<div class="flash flash-err">{{ error }}</div>{% endif %}
  <div class="card" style="max-width:500px">
    <form method="POST">
      <div class="field"><label>Datum</label><input type="date" name="date" value="{{ exp.date or today }}" required></div>
      <div class="field"><label>Categorie</label><select name="category">
        {% for cat in categories %}<option value="{{ cat }}" {{ 'selected' if exp.category==cat }}>{{ cat }}</option>{% endfor %}
      </select></div>
      <div class="field"><label>Omschrijving</label><input type="text" name="description" value="{{ exp.description or '' }}"></div>
      <div class="field"><label>Bedrag excl. BTW</label><input type="number" name="amount_excl" step="0.01" min="0" value="{{ exp.amount_excl or '' }}" required></div>
      <div class="field"><label>BTW (€)</label><input type="number" name="btw" step="0.01" min="0" value="{{ exp.btw or '0' }}"></div>
      <button class="btn btn-primary">{{ 'Opslaan' if edit else 'Toevoegen' }}</button>
      <a href="{{ url_for('expenses') }}" class="btn" style="background:#E5E7EB;color:#1F2937;margin-left:8px">Annuleren</a>
    </form>
  </div>
</div>
{% endblock %}
""")

# ── BTW ─────────────────────────────────────────────────────────────────────
BTW_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header"><span style="font-weight:700">BTW-overzicht</span><button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button></div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}" class="active">📋 BTW-overzicht</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for(\'logout\') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header"><h1>BTW-overzicht {{ year }}</h1></div>
  <div class="card" style="overflow-x:auto">
    <table>
      <tr><th>Kwartaal</th><th>BTW op facturen</th><th>BTW op kosten</th><th>Netto verschil</th><th>Deadline</th><th>Status</th><th>Actie</th></tr>
      {% for q in quarters %}
      <tr>
        <td><strong>Q{{ q.quarter }}</strong></td>
        <td>{{ fmt(q.btw_in) }}</td><td>{{ fmt(q.btw_out) }}</td>
        <td style="font-weight:600;color:{% if q.net >= 0 %}#EF4444{% else %}#00A859{% endif %}">{{ fmt(q.net) }}</td>
        <td>{{ q.deadline }}</td>
        <td><span class="badge {% if q.status=='Gedaan' %}badge-green{% else %}badge-yellow{% endif %}">{{ q.status }}</span></td>
        <td>
          <form method="POST" action="{{ url_for('btw_toggle', year=year, quarter=q.quarter) }}">
            <button class="btn btn-sm {% if q.status=='Gedaan' %}btn-warning{% else %}btn-success{% endif %}">{% if q.status=='Gedaan' %}↩️ Open{% else %}✅ Gedaan{% endif %}</button>
          </form>
        </td>
      </tr>{% endfor %}
    </table>
  </div>
</div>
{% endblock %}
""")

# ── Settings ────────────────────────────────────────────────────────────────
SETTINGS_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header"><span style="font-weight:700">Instellingen</span><button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button></div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <a href="{{ url_for('settings_page') }}" class="active">⚙️ Instellingen</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for(\'logout\') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header"><h1>Instellingen</h1></div>
  {% if msg %}<div class="flash flash-ok">{{ msg }}</div>{% endif %}
  <form method="POST">
  <div class="grid grid-2">
    <div class="card">
      <h3>Bedrijfsgegevens</h3>
      <div class="field"><label>Bedrijfsnaam</label><input type="text" name="company_name" value="{{ s.company_name }}"></div>
      <div class="field"><label>Adres</label><input type="text" name="company_address" value="{{ s.company_address }}"></div>
      <div class="field"><label>KvK</label><input type="text" name="company_kvk" value="{{ s.company_kvk }}"></div>
      <div class="field"><label>BTW-nummer</label><input type="text" name="company_btw" value="{{ s.company_btw }}"></div>
      <div class="field"><label>Bankrekening</label><input type="text" name="company_bank" value="{{ s.company_bank }}"></div>
    </div>
    <div class="card">
      <h3>Tarieven & Voorwaarden</h3>
      <div class="field"><label>Uurtarief Phoenix Metals (€)</label><input type="number" name="rate_phoenix_metals" step="1" value="{{ s.rate_phoenix_metals }}"></div>
      <div class="field"><label>Uurtarief Club of Engineers (€)</label><input type="number" name="rate_club_of_engineers" step="1" value="{{ s.rate_club_of_engineers }}"></div>
      <div class="field"><label>Uurtarief Overig (€)</label><input type="number" name="rate_overig" step="1" value="{{ s.rate_overig }}"></div>
      <div class="field"><label>Betalingsvoorwaarden (dagen)</label><input type="number" name="payment_terms" value="{{ s.payment_terms }}"></div>
      <div class="field"><label>Adres Phoenix Metals</label><input type="text" name="client_phoenix_metals_address" value="{{ s.client_phoenix_metals_address }}"></div>
      <div class="field"><label>Adres Club of Engineers</label><input type="text" name="client_club_of_engineers_address" value="{{ s.client_club_of_engineers_address }}"></div>
      <div class="field"><label>Adres Overig</label><input type="text" name="client_overig_address" value="{{ s.client_overig_address }}"></div>
      <div class="field"><label>Kilometertarief (€)</label><input type="number" name="travel_rate" step="0.01" min="0" value="{{ s.travel_rate }}"><small style="color:#6B7280;font-size:11px">Belastingdienst 2025: €0.23/km</small></div>
    </div>
  </div>
  <button class="btn btn-primary" style="margin-top:8px">Opslaan</button>
  </form>
</div>
{% endblock %}
""")


# ── Travel Costs ────────────────────────────────────────────────────────────
TRAVEL_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header">
  <span style="font-weight:700">Reiskosten</span>
  <button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button>
</div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}" class="active">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header" style="display:flex;justify-content:space-between;align-items:center">
    <h1>Reiskosten</h1>
    <a href="{{ url_for('travel_add') }}" class="btn btn-primary">+ Rit toevoegen</a>
  </div>
  {% if msg %}<div class="flash flash-ok">{{ msg }}</div>{% endif %}
  <div class="card">
    <div style="display:flex;gap:12px;align-items:center;margin-bottom:16px;flex-wrap:wrap">
      <label style="font-size:13px;font-weight:600">Filter:</label>
      <select id="filter_client" onchange="applyFilter()" style="padding:6px 10px;border:1px solid #E5E7EB;border-radius:6px;font-size:13px">
        <option value="">Alle opdrachtgevers</option><option value="Phoenix Metals">Phoenix Metals</option><option value="Club of Engineers">Club of Engineers</option><option value="Overig">Overig</option><option value="Overhead">Overhead</option>
      </select>
      <select id="filter_month" onchange="applyFilter()" style="padding:6px 10px;border:1px solid #E5E7EB;border-radius:6px;font-size:13px">
        <option value="">Alle maanden</option>
        {% for m in months %}<option value="{{ m }}">{{ m }}</option>{% endfor %}
      </select>
      <span style="margin-left:auto;font-size:13px;color:#6B7280">Totaal getoond: <strong id="shown_km">0</strong> km / <strong id="shown_eur">€ 0,00</strong></span>
    </div>
    <div style="overflow-x:auto">
    <table>
      <tr><th>Datum</th><th>Opdrachtgever</th><th>Van</th><th>Naar</th><th>KM</th><th>Type</th><th>Bedrag</th><th>Facturabel</th><th>Acties</th></tr>
      {% for t in travels %}
      <tr data-client="{{ t.client }}" data-month="{{ t.date[:7] }}" data-km="{{ t.km }}" data-amount="{{ t.amount }}">
        <td>{{ t.date }}</td><td>{{ t.client or '—' }}</td><td>{{ t.from_location or '—' }}</td><td>{{ t.to_location or '—' }}</td>
        <td>{{ t.km }}</td><td>{{ t.transport_type }}</td><td>{{ fmt(t.amount) }}</td>
        <td>{% if t.billable %}<span class="badge badge-green">Ja</span>{% else %}<span class="badge badge-yellow">Nee</span>{% endif %}</td>
        <td class="actions">
          <a href="{{ url_for('travel_edit', tid=t.id) }}" class="btn btn-accent btn-sm">✏️</a>
          <form method="POST" action="{{ url_for('travel_delete', tid=t.id) }}" style="display:inline" onsubmit="return confirm('Verwijderen?')"><button class="btn btn-danger btn-sm">🗑️</button></form>
        </td>
      </tr>{% endfor %}
    </table>
    </div>
  </div>
  <div class="grid grid-3">
    <div class="card"><h3>Totaal kilometers</h3><div class="big">{{ total_km|round(0) }} km</div></div>
    <div class="card"><h3>Totaal bedrag</h3><div class="big green">{{ fmt(total_amount) }}</div></div>
    <div class="card"><h3>Facturabel</h3><div class="big orange">{{ fmt(billable_amount) }}</div></div>
  </div>
</div>
<script>
function applyFilter(){
  var c=document.getElementById('filter_client').value, m=document.getElementById('filter_month').value;
  var totKm=0, totEur=0;
  document.querySelectorAll('table tr[data-client]').forEach(function(r){
    var show=(!c||r.dataset.client===c)&&(!m||r.dataset.month===m);
    r.style.display=show?'':'none';
    if(show){totKm+=parseFloat(r.dataset.km);totEur+=parseFloat(r.dataset.amount);}
  });
  document.getElementById('shown_km').textContent=totKm.toFixed(0);
  document.getElementById('shown_eur').textContent='€ '+totEur.toFixed(2).replace('.',',');
}
applyFilter();
</script>
{% endblock %}
""")

TRAVEL_FORM_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header"><span style="font-weight:700">{{ 'Rit bewerken' if edit else 'Rit toevoegen' }}</span><button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button></div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}" class="active">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('zzp_advisor') }}">💡 ZZP Advisor</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a></div>
</div>
<div class="main">
  <div class="page-header"><h1>{{ 'Rit bewerken' if edit else 'Rit toevoegen' }}</h1></div>
  {% if error %}<div class="flash flash-err">{{ error }}</div>{% endif %}
  <div class="card" style="max-width:500px">
    <form method="POST">
      <div class="field"><label>Datum</label><input type="date" name="date" value="{{ t.date or today }}" required></div>
      <div class="field"><label>Opdrachtgever</label><select name="client">
        <option value="" {{ 'selected' if not t.client }}>—</option>
        <option value="Phoenix Metals" {{ 'selected' if t.client=='Phoenix Metals' }}>Phoenix Metals</option>
        <option value="Club of Engineers" {{ 'selected' if t.client=='Club of Engineers' }}>Club of Engineers</option>
        <option value="Overig" {{ 'selected' if t.client=='Overig' }}>Overig</option>
        <option value="Overhead" {{ 'selected' if t.client=='Overhead' }}>Overhead</option>
      </select></div>
      <div class="field"><label>Vertrek (van)</label><input type="text" name="from_location" value="{{ t.from_location or '' }}" placeholder="bijv. Heiloo"></div>
      <div class="field"><label>Bestemming (naar)</label><input type="text" name="to_location" value="{{ t.to_location or '' }}" placeholder="bijv. IJmuiden"></div>
      <div class="grid grid-2">
        <div class="field"><label>Kilometers</label><input type="number" name="km" step="0.5" min="0" value="{{ t.km or '' }}" id="km_input" required oninput="calcAmount()"></div>
        <div class="field"><label>Transport</label><select name="transport_type" id="transport_type">
          <option value="Auto" {{ 'selected' if t.transport_type=='Auto' or not t.transport_type }}>Auto</option>
          <option value="OV" {{ 'selected' if t.transport_type=='OV' }}>Openbaar Vervoer</option>
          <option value="Fiets" {{ 'selected' if t.transport_type=='Fiets' }}>Fiets</option>
          <option value="Overig" {{ 'selected' if t.transport_type=='Overig' }}>Overig</option>
        </select></div>
      </div>
      <div class="grid grid-2">
        <div class="field"><label>Tarief per km (€)</label><input type="number" name="rate_per_km" step="0.01" min="0" value="{{ t.rate_per_km if edit else rate }}" id="rate_input" oninput="calcAmount()"></div>
        <div class="field"><label>Bedrag (€)</label><input type="text" id="amount_display" value="€ 0,00" readonly style="background:#F3F4F6;font-weight:600"></div>
      </div>
      <input type="hidden" name="amount" id="amount_hidden" value="{{ t.amount or '0' }}">
      <div class="field"><label>Facturabel</label><select name="billable">
        <option value="1" {{ 'selected' if t.billable!=0 }}>Ja</option>
        <option value="0" {{ 'selected' if t.billable==0 and edit }}>Nee</option>
      </select></div>
      <div class="field"><label>Doel / Opmerking</label><textarea name="purpose">{{ t.purpose or '' }}</textarea></div>
      <button class="btn btn-primary" type="submit">{{ 'Opslaan' if edit else 'Toevoegen' }}</button>
      <a href="{{ url_for('travel') }}" class="btn" style="background:#E5E7EB;color:#1F2937;margin-left:8px">Annuleren</a>
    </form>
  </div>
</div>
<script>
function calcAmount(){
  var km=parseFloat(document.getElementById('km_input').value)||0;
  var rate=parseFloat(document.getElementById('rate_input').value)||0;
  var amount=km*rate;
  document.getElementById('amount_display').value='€ '+amount.toFixed(2).replace('.',',');
  document.getElementById('amount_hidden').value=amount.toFixed(2);
}
calcAmount();
</script>
{% endblock %}
""")

# ════════════════════════════════════════════════════════════════════════════
# ROUTES
# ════════════════════════════════════════════════════════════════════════════

@app.route('/zzp/login', methods=['GET','POST'])
def login():
    if request.method == 'POST':
        r = get_db().execute("SELECT * FROM users WHERE username=?", (request.form['username'],)).fetchone()
        if r and check_password_hash(r['password_hash'], request.form['password']):
            session.permanent = True
            session['user'] = r['username']
            return redirect(url_for('dashboard'))
        return render_template_string(LOGIN_TMPL, error='Ongeldige inloggegevens')
    return render_template_string(LOGIN_TMPL, error=None)

@app.route('/zzp/logout')
def logout():
    session.clear()
    return redirect(url_for('login'))

# ── Dashboard ───────────────────────────────────────────────────────────────
@app.route('/zzp/')
@login_required
def dashboard():
    db = get_db()
    year = datetime.now().year
    # Hours
    r = db.execute("SELECT COALESCE(SUM(hours),0) as h FROM timesheets WHERE date LIKE ?",
                   (f"{year}%",)).fetchone()
    total_hours = r['h']
    r = db.execute("SELECT COALESCE(SUM(hours),0) as h FROM timesheets WHERE date LIKE ? AND billable=1",
                   (f"{year}%",)).fetchone()
    billable_hours = r['h']
    overhead_hours = total_hours - billable_hours
    pct = (total_hours / 1225) * 100 if total_hours else 0
    # Invoices
    open_inv = db.execute("SELECT COUNT(*) as c FROM invoices WHERE status IN ('Verstuurd','Over tijdig') AND invoice_date LIKE ?",
                          (f"{year}%",)).fetchone()['c']
    # Revenue & expenses
    rev = db.execute("SELECT COALESCE(SUM(total),0) as t FROM invoices WHERE status='Betaald' AND invoice_date LIKE ?",
                     (f"{year}%",)).fetchone()['t']
    exp = db.execute("SELECT COALESCE(SUM(total),0) as t FROM expenses WHERE date LIKE ?",
                     (f"{year}%",)).fetchone()['t']
    profit = rev - exp
    btw_reserve = calc_btw_reserve()
    # Recent
    recent = db.execute("SELECT * FROM timesheets ORDER BY date DESC LIMIT 5").fetchall()
    # Alerts
    alerts = []
    overdue = db.execute("SELECT invoice_number, due_date FROM invoices WHERE status='Verstuurd' AND due_date < date('now')").fetchall()
    for o in overdue:
        alerts.append({'text': f"⚠️ Factuur {o['invoice_number']} is achterstallig ( vervaldatum {o['due_date']})", 'style': 'color:%s' % C['danger']})
    # BTW deadline
    now = datetime.now()
    q = (now.month - 1) // 3 + 1
    deadlines = {1: '30 april', 2: '31 juli', 3: '31 oktober', 4: '31 januari'}
    btws = db.execute("SELECT * FROM btw_quarters WHERE year=? AND quarter=? AND status='Nog doen'", (year, q)).fetchall()
    if btws:
        alerts.append({'text': f"📋 BTW Q{q} deadline: {deadlines[q]}", 'style': 'color:%s' % C['warning']})

    # Travel costs
    travel_total = db.execute("SELECT COALESCE(SUM(amount),0) as t FROM travel_logs WHERE date LIKE ?", (f"{year}%",)).fetchone()['t']
    travel_km = db.execute("SELECT COALESCE(SUM(km),0) as k FROM travel_logs WHERE date LIKE ?", (f"{year}%",)).fetchone()['k']
    data = dict(total_hours=total_hours, billable_hours=billable_hours, overhead_hours=overhead_hours,
                pct=pct, open_invoices=open_inv, profit=profit, btw_reserve=btw_reserve,
                travel_total=travel_total, travel_km=travel_km)
    return render_template_string(DASHBOARD_TMPL, data=data, recent=recent, alerts=alerts,
                                  fmt=fmt_eur)

# ── Timesheets ──────────────────────────────────────────────────────────────
@app.route('/zzp/timesheets')
@login_required
def timesheets():
    db = get_db()
    year = datetime.now().year
    rows = db.execute("SELECT * FROM timesheets WHERE date LIKE ? ORDER BY date DESC", (f"{year}%",)).fetchall()
    r = db.execute("SELECT COALESCE(SUM(hours),0) as h FROM timesheets WHERE date LIKE ?", (f"{year}%",)).fetchone()
    total = r['h']
    r = db.execute("SELECT COALESCE(SUM(hours),0) as h FROM timesheets WHERE date LIKE ? AND billable=1", (f"{year}%",)).fetchone()
    billable = r['h']
    months = sorted(set(r['date'][:7] for r in rows), reverse=True) if rows else []
    return render_template_string(TIMESHEETS_TMPL, timesheets=rows, total_hours=total,
                                  billable_hours=billable, months=months, msg=request.args.get('msg'))

@app.route('/zzp/timesheets/add', methods=['GET','POST'])
@login_required
def timesheet_add():
    if request.method == 'POST':
        get_db().execute("INSERT INTO timesheets (date,client,activity,hours,billable,note) VALUES (?,?,?,?,?,?)",
                         (request.form['date'], request.form['client'], request.form['activity'],
                          float(request.form['hours']), int(request.form.get('billable',1)), request.form.get('note','')))
        get_db().commit()
        return redirect(url_for('timesheets', msg='Uren toegevoegd'))
    return render_template_string(TIMESHEET_FORM_TMPL, edit=False, ts=None,
                                  today=datetime.now().strftime('%Y-%m-%d'))

@app.route('/zzp/timesheets/edit/<int:tid>', methods=['GET','POST'])
@login_required
def timesheet_edit(tid):
    db = get_db()
    if request.method == 'POST':
        db.execute("UPDATE timesheets SET date=?,client=?,activity=?,hours=?,billable=?,note=? WHERE id=?",
                   (request.form['date'], request.form['client'], request.form['activity'],
                    float(request.form['hours']), int(request.form.get('billable',1)),
                    request.form.get('note',''), tid))
        db.commit()
        return redirect(url_for('timesheets', msg='Uren bijgewerkt'))
    ts = db.execute("SELECT * FROM timesheets WHERE id=?", (tid,)).fetchone()
    return render_template_string(TIMESHEET_FORM_TMPL, edit=True, ts=ts, today=ts['date'])

@app.route('/zzp/timesheets/delete/<int:tid>', methods=['POST'])
@login_required
def timesheet_delete(tid):
    get_db().execute("DELETE FROM timesheets WHERE id=?", (tid,))
    get_db().commit()
    return redirect(url_for('timesheets', msg='Uren verwijderd'))

# ── Invoices ────────────────────────────────────────────────────────────────
@app.route('/zzp/invoices')
@login_required
def invoices():
    db = get_db()
    invs = db.execute("SELECT * FROM invoices ORDER BY id DESC").fetchall()
    total_invoiced = db.execute("SELECT COALESCE(SUM(total),0) as t FROM invoices").fetchone()['t']
    total_paid = db.execute("SELECT COALESCE(SUM(total),0) as t FROM invoices WHERE status='Betaald'").fetchone()['t']
    return render_template_string(INVOICES_TMPL, invoices=invs, fmt=fmt_eur,
                                  total_invoiced=total_invoiced, total_paid=total_paid,
                                  total_open=total_invoiced - total_paid, msg=request.args.get('msg'))

@app.route('/zzp/invoices/generate', methods=['GET','POST'])
@login_required
def invoice_generate():
    db = get_db()
    if request.method == 'POST':
        client = request.form['client']
        year = int(request.form['year'])
        month = int(request.form['month'])
        inv_date = request.form['invoice_date']
        prefix = client_prefix(client)
        rate_key = f'rate_{client.lower().replace(" ","_")}'
        rate = float(get_setting(rate_key, '100'))
        # Get billable hours for this period
        rows = db.execute("SELECT activity, SUM(hours) as hours FROM timesheets WHERE client=? AND billable=1 AND date LIKE ? GROUP BY activity",
                          (client, f"{year}-{month:02d}%")).fetchall()
        if not rows:
            return render_template_string(INVOICE_GENERATE_TMPL, error='Geen facturabele uren gevonden voor deze periode/opdrachtgever.',
                                          year=year, month=month, today=inv_date, preview=None)
        inv_num = next_invoice_number(client, year)
        terms = int(get_setting('payment_terms','30'))
        due_date = (datetime.strptime(inv_date, '%Y-%m-%d') + timedelta(days=terms)).strftime('%Y-%m-%d')
        subtotal = sum(r['hours'] * rate for r in rows)
        btw = subtotal * 0.21
        total = subtotal + btw
        db.execute("INSERT INTO invoices (invoice_number,client,period_year,period_month,invoice_date,due_date,subtotal,btw,total) VALUES (?,?,?,?,?,?,?,?,?)",
                   (inv_num, client, year, month, inv_date, due_date, subtotal, btw, total))
        inv_id = db.execute("SELECT last_insert_rowid()").fetchone()[0]
        for r in rows:
            db.execute("INSERT INTO invoice_lines (invoice_id,description,hours,rate,amount) VALUES (?,?,?,?,?)",
                       (inv_id, r['activity'], r['hours'], rate, r['hours'] * rate))
        db.commit()
        return redirect(url_for('invoices', msg=f'Factuur {inv_num} gegenereerd'))
    today = datetime.now().strftime('%Y-%m-%d')
    return render_template_string(INVOICE_GENERATE_TMPL, error=None,
                                  year=datetime.now().year, month=datetime.now().month,
                                  today=today, preview=None)

@app.route('/zzp/invoices/view/<int:iid>')
@login_required
def invoice_view(iid):
    db = get_db()
    inv = db.execute("SELECT * FROM invoices WHERE id=?", (iid,)).fetchone()
    lines = db.execute("SELECT * FROM invoice_lines WHERE invoice_id=?", (iid,)).fetchall()
    client_addr_key = f'client_{inv["client"].lower().replace(" ","_")}_address'
    client_addr = get_setting(client_addr_key, '')
    return render_template_string(INVOICE_VIEW_TMPL, inv=inv, lines=lines, fmt=fmt_eur,
                                  company_name=get_setting('company_name'),
                                  company_address=get_setting('company_address'),
                                  company_kvk=get_setting('company_kvk'),
                                  company_btw=get_setting('company_btw'),
                                  company_bank=get_setting('company_bank'),
                                  payment_terms=get_setting('payment_terms','30'),
                                  client_address=client_addr)

@app.route('/zzp/invoices/status/<int:iid>', methods=['POST'])
@login_required
def invoice_status(iid):
    get_db().execute("UPDATE invoices SET status=? WHERE id=?", (request.form['status'], iid))
    get_db().commit()
    return redirect(url_for('invoices'))

@app.route('/zzp/invoices/delete/<int:iid>', methods=['POST'])
@login_required
def invoice_delete(iid):
    db = get_db()
    db.execute("DELETE FROM invoice_lines WHERE invoice_id=?", (iid,))
    db.execute("DELETE FROM invoices WHERE id=?", (iid,))
    db.commit()
    return redirect(url_for('invoices', msg='Factuur verwijderd'))

# ── Expenses ────────────────────────────────────────────────────────────────
EXPENSE_CATEGORIES = ['Boekhouper','Verzekeringen','Reiskosten','Software','Hardware','Opleiding','Kantoor','Overig']

@app.route('/zzp/expenses')
@login_required
def expenses():
    db = get_db()
    year = datetime.now().year
    rows = db.execute("SELECT * FROM expenses WHERE date LIKE ? ORDER BY date DESC", (f"{year}%",)).fetchall()
    total_exp = db.execute("SELECT COALESCE(SUM(total),0) as t FROM expenses WHERE date LIKE ?", (f"{year}%",)).fetchone()['t']
    total_btw_exp = db.execute("SELECT COALESCE(SUM(btw),0) as t FROM expenses WHERE date LIKE ?", (f"{year}%",)).fetchone()['t']
    # Monthly overview
    monthly = []
    for m in range(1,13):
        label = f"{year}-{m:02d}"
        rev = db.execute("SELECT COALESCE(SUM(subtotal),0) as t FROM invoices WHERE invoice_date LIKE ?", (f"{label}%",)).fetchone()['t']
        exp_m = db.execute("SELECT COALESCE(SUM(total),0) as t FROM expenses WHERE date LIKE ?", (f"{label}%",)).fetchone()['t']
        monthly.append({'label': label, 'revenue': rev, 'expenses': exp_m, 'profit': rev - exp_m})
    return render_template_string(EXPENSES_TMPL, expenses=rows, total_expenses=total_exp,
                                  total_btw=total_btw_exp, monthly=monthly, year=year,
                                  fmt=fmt_eur, msg=request.args.get('msg'))

@app.route('/zzp/expenses/add', methods=['GET','POST'])
@login_required
def expense_add():
    if request.method == 'POST':
        excl = float(request.form['amount_excl'])
        btw = float(request.form.get('btw','0'))
        get_db().execute("INSERT INTO expenses (date,category,description,amount_excl,btw,total) VALUES (?,?,?,?,?,?)",
                         (request.form['date'], request.form['category'], request.form.get('description',''),
                          excl, btw, excl + btw))
        get_db().commit()
        return redirect(url_for('expenses', msg='Kosten toegevoegd'))
    return render_template_string(EXPENSE_FORM_TMPL, edit=False, exp=None,
                                  today=datetime.now().strftime('%Y-%m-%d'),
                                  categories=EXPENSE_CATEGORIES)

@app.route('/zzp/expenses/edit/<int:eid>', methods=['GET','POST'])
@login_required
def expense_edit(eid):
    db = get_db()
    if request.method == 'POST':
        excl = float(request.form['amount_excl'])
        btw = float(request.form.get('btw','0'))
        db.execute("UPDATE expenses SET date=?,category=?,description=?,amount_excl=?,btw=?,total=? WHERE id=?",
                   (request.form['date'], request.form['category'], request.form.get('description',''),
                    excl, btw, excl + btw, eid))
        db.commit()
        return redirect(url_for('expenses', msg='Kosten bijgewerkt'))
    exp = db.execute("SELECT * FROM expenses WHERE id=?", (eid,)).fetchone()
    return render_template_string(EXPENSE_FORM_TMPL, edit=True, exp=exp, today=exp['date'],
                                  categories=EXPENSE_CATEGORIES)

@app.route('/zzp/expenses/delete/<int:eid>', methods=['POST'])
@login_required
def expense_delete(eid):
    get_db().execute("DELETE FROM expenses WHERE id=?", (eid,))
    get_db().commit()
    return redirect(url_for('expenses', msg='Kosten verwijderd'))

# ── Travel Costs ────────────────────────────────────────────────────────────
@app.route('/zzp/travel')
@login_required
def travel():
    db = get_db()
    year = datetime.now().year
    rows = db.execute("SELECT * FROM travel_logs WHERE date LIKE ? ORDER BY date DESC", (f"{year}%",)).fetchall()
    total_km = db.execute("SELECT COALESCE(SUM(km),0) as k FROM travel_logs WHERE date LIKE ?", (f"{year}%",)).fetchone()['k']
    total_amount = db.execute("SELECT COALESCE(SUM(amount),0) as t FROM travel_logs WHERE date LIKE ?", (f"{year}%",)).fetchone()['t']
    billable_amount = db.execute("SELECT COALESCE(SUM(amount),0) as t FROM travel_logs WHERE date LIKE ? AND billable=1", (f"{year}%",)).fetchone()['t']
    months = sorted(set(r['date'][:7] for r in rows), reverse=True) if rows else []
    return render_template_string(TRAVEL_TMPL, travels=rows, total_km=total_km,
                                  total_amount=total_amount, billable_amount=billable_amount,
                                  months=months, fmt=fmt_eur, msg=request.args.get('msg'))

@app.route('/zzp/travel/add', methods=['GET','POST'])
@login_required
def travel_add():
    if request.method == 'POST':
        km = float(request.form['km'])
        rate = float(request.form.get('rate_per_km', '0.23'))
        amount = round(km * rate, 2)
        get_db().execute(
            "INSERT INTO travel_logs (date,client,from_location,to_location,km,rate_per_km,amount,transport_type,purpose,billable) VALUES (?,?,?,?,?,?,?,?,?,?)",
            (request.form['date'], request.form.get('client',''), request.form.get('from_location',''),
             request.form.get('to_location',''), km, rate, amount,
             request.form.get('transport_type','Auto'), request.form.get('purpose',''),
             int(request.form.get('billable',1))))
        get_db().commit()
        return redirect(url_for('travel', msg='Rit toegevoegd'))
    return render_template_string(TRAVEL_FORM_TMPL, edit=False, t=None,
                                  today=datetime.now().strftime('%Y-%m-%d'),
                                  rate=get_setting('travel_rate','0.23'))

@app.route('/zzp/travel/edit/<int:tid>', methods=['GET','POST'])
@login_required
def travel_edit(tid):
    db = get_db()
    if request.method == 'POST':
        km = float(request.form['km'])
        rate = float(request.form.get('rate_per_km', '0.23'))
        amount = round(km * rate, 2)
        db.execute(
            "UPDATE travel_logs SET date=?,client=?,from_location=?,to_location=?,km=?,rate_per_km=?,amount=?,transport_type=?,purpose=?,billable=? WHERE id=?",
            (request.form['date'], request.form.get('client',''), request.form.get('from_location',''),
             request.form.get('to_location',''), km, rate, amount,
             request.form.get('transport_type','Auto'), request.form.get('purpose',''),
             int(request.form.get('billable',1)), tid))
        db.commit()
        return redirect(url_for('travel', msg='Rit bijgewerkt'))
    t = db.execute("SELECT * FROM travel_logs WHERE id=?", (tid,)).fetchone()
    return render_template_string(TRAVEL_FORM_TMPL, edit=True, t=t, today=t['date'],
                                  rate=get_setting('travel_rate','0.23'))

@app.route('/zzp/travel/delete/<int:tid>', methods=['POST'])
@login_required
def travel_delete(tid):
    get_db().execute("DELETE FROM travel_logs WHERE id=?", (tid,))
    get_db().commit()
    return redirect(url_for('travel', msg='Rit verwijderd'))

# ── BTW ─────────────────────────────────────────────────────────────────────
@app.route('/zzp/btw')
@login_required
def btw():
    db = get_db()
    year = datetime.now().year
    quarters = []
    deadlines_map = {1: '30 april', 2: '31 juli', 3: '31 oktober', 4: '31 januari'}
    for q in range(1,5):
        m_start = (q-1)*3+1
        m_end = q*3
        patterns = [f"{year}-{m:02d}%" for m in range(m_start, m_end+1)]
        btw_in = 0
        btw_out = 0
        for p in patterns:
            r = db.execute("SELECT COALESCE(SUM(btw),0) as t FROM invoices WHERE invoice_date LIKE ?", (p,)).fetchone()
            btw_in += r['t']
            r = db.execute("SELECT COALESCE(SUM(btw),0) as t FROM expenses WHERE date LIKE ?", (p,)).fetchone()
            btw_out += r['t']
        r = db.execute("SELECT * FROM btw_quarters WHERE year=? AND quarter=?", (year, q)).fetchone()
        status = r['status'] if r else 'Nog doen'
        quarters.append({'quarter': q, 'btw_in': btw_in, 'btw_out': btw_out,
                        'net': btw_in - btw_out, 'deadline': deadlines_map[q], 'status': status})
    return render_template_string(BTW_TMPL, quarters=quarters, year=year, fmt=fmt_eur)

@app.route('/zzp/btw/toggle/<int:year>/<int:quarter>', methods=['POST'])
@login_required
def btw_toggle(year, quarter):
    db = get_db()
    r = db.execute("SELECT * FROM btw_quarters WHERE year=? AND quarter=?", (year, quarter)).fetchone()
    if r:
        new_status = 'Nog doen' if r['status'] == 'Gedaan' else 'Gedaan'
        db.execute("UPDATE btw_quarters SET status=?, filed_at=? WHERE year=? AND quarter=?",
                   (new_status, datetime.now().isoformat() if new_status=='Gedaan' else None, year, quarter))
    else:
        db.execute("INSERT INTO btw_quarters (year,quarter,status) VALUES (?,?,?)",
                   (year, quarter, 'Gedaan'))
    db.commit()
    return redirect(url_for('btw'))

# ── Settings ────────────────────────────────────────────────────────────────
SETTINGS_KEYS = ['company_name','company_address','company_kvk','company_btw','company_bank',
                 'rate_phoenix_metals','rate_club_of_engineers','rate_overig','payment_terms',
                 'client_phoenix_metals_address','client_club_of_engineers_address','client_overig_address',
                 'travel_rate']

@app.route('/zzp/settings', methods=['GET','POST'])
@login_required
def settings_page():
    if request.method == 'POST':
        for k in SETTINGS_KEYS:
            if k in request.form:
                set_setting(k, request.form[k])
        return render_template_string(SETTINGS_TMPL, msg='Instellingen opgeslagen',
                                      s={k: get_setting(k) for k in SETTINGS_KEYS})
    return render_template_string(SETTINGS_TMPL, msg=None,
                                  s={k: get_setting(k) for k in SETTINGS_KEYS})

# ── Run ─────────────────────────────────────────────────────────────────────
init_db()

# ── ZZP Advisor AI ────────────────────────────────────────────────────────────
ZAI_URL = os.environ.get('AI_API_URL', 'https://api.z.ai/api/coding/paas/v4/chat/completions')
ZAI_KEY = os.environ.get('AI_API_KEY', '43a6c7e3d7b240daafae006e8488f674.ivYYRRLySgUwgqVE')
ZAI_MODEL = os.environ.get('AI_MODEL', 'glm-5-turbo')
OR_URL = os.environ.get('OPENROUTER_URL', 'https://openrouter.ai/api/v1/chat/completions')
OR_KEY = os.environ.get('OPENROUTER_API_KEY', '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')
OR_MODEL = os.environ.get('OPENROUTER_MODEL', 'google/gemma-3-27b-it:free')
TAVILY_KEY = os.environ.get('TAVILY_API_KEY', '')

ZZP_SYSTEM = """Je bent een Nederlandse ZZP Adviseur. antwoord ALLEEN in het Nederlands.

Je geeft concreet, feitelijk advies over ondernemerschap in Nederland. Gebruik cijfers, percentages en termijnen. Verwijs naar Belastingdienst, KVK of UWV waar relevant.

Expertise: KVK-inschrijving, BTW (21%/9%/0%), inkomstenbelasting, IZB, MKB-winstvrijstelling, facturatie vereisten, DBA-wetgeving, modelovereenkomsten, pensioen (lijfrente), AOV-verzekering, contracten, auto/fiets fiscaliteit, KIA afschrijving, urencriterium (1.225 uur).

REGELS:
- Antwoord DIRECT met het antwoord. Geen inleiding, geen meta-tekst, geen "Analyze" of "Drafting".
- Gebruik opsommingen met bullet points.
- Als je niet zeker bent, zeg dat dan.
- NOOIT Engels. ALTIJD Nederlands."""

def ai_call(messages, max_retries=2):
    """AI call with retry + fallback — same architecture as HSEQ dashboard."""
    import time as _time
    providers = [
        ('zai', ZAI_URL, ZAI_KEY, ZAI_MODEL, True),
        ('or', OR_URL, OR_KEY, OR_MODEL, False),
    ]
    for pname, url, key, model, use_ctx in providers:
        for attempt in range(max_retries):
            try:
                payload = json.dumps({"model":model,"messages":messages,"stream":False,"temperature":0.7,"max_tokens":4000}).encode('utf-8')
                headers = {"Content-Type":"application/json","Authorization":f"Bearer {key}"}
                if pname == 'or':
                    headers["HTTP-Referer"] = "https://mescalinerabbit.shop"
                    headers["X-Title"] = "ZZP Advisor"
                req = urllib.request.Request(url, data=payload, headers=headers)
                if use_ctx:
                    ctx = ssl.create_default_context()
                    ctx.check_hostname = False
                    ctx.verify_mode = ssl.CERT_NONE
                    resp = urllib.request.urlopen(req, context=ctx, timeout=120)
                else:
                    resp = urllib.request.urlopen(req, timeout=60)
                return resp
            except urllib.error.HTTPError as e:
                body = e.read().decode('utf-8', errors='replace')[:200]
                print(f'[ZZP AI] {pname} HTTP {e.code} attempt {attempt+1}/{max_retries}: {body}')
                if attempt < max_retries - 1:
                    _time.sleep(2 ** attempt)
                else:
                    break
            except Exception as e:
                print(f'[ZZP AI] {pname} error attempt {attempt+1}: {e}')
                if attempt < max_retries - 1:
                    _time.sleep(2 ** attempt)
                else:
                    break
    return None

def ai_complete(messages):
    """Non-streaming AI call with retry — HSEQ dashboard architecture."""
    resp = ai_call(messages)
    if resp is None:
        return '⚠️ Momenteel zijn alle AI-modellen bezet. Probeer het over een minuut opnieuw.'
    data = json.loads(resp.read().decode('utf-8'))
    msg = data['choices'][0]['message']
    content = msg.get('content', '')
    if not content:
        content = msg.get('reasoning_content', '')
    return content

# ── ZZP Advisor Page ────────────────────────────────────────────────────────
ADVISOR_TMPL = LAYOUT.replace('{% block body %}{% endblock %}', """
{% block body %}
<div class="mobile-header"><span style="font-weight:700">ZZP Advisor</span><div style="display:flex;gap:12px;align-items:center"><a href="javascript:void(0)" onclick="clearChat()" title="Wis chat" style="color:rgba(255,255,255,.6);font-size:18px;text-decoration:none">🗑️</a><button class="menu-btn" onclick="document.querySelector('.sidebar').style.display=document.querySelector('.sidebar').style.display==='flex'?'none':'flex'">☰</button></div></div>
<div class="sidebar">
  <div class="logo">ZZP Dashboard<small>JG Consultancy</small></div>
  <nav>
    <a href="{{ url_for('dashboard') }}">📊 Dashboard</a>
    <a href="{{ url_for('timesheets') }}">⏱️ Urenregistratie</a>
    <a href="{{ url_for('invoices') }}">📄 Facturatie</a>
    <a href="{{ url_for('expenses') }}">💰 Kosten</a>
    <a href="{{ url_for('travel') }}">🚗 Reiskosten</a>
    <a href="{{ url_for('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('zzp_advisor') }}" class="active">💡 ZZP Advisor</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
    <div style="border-top:1px solid rgba(255,255,255,.2);margin:8px 0"></div>
    <a href="{{ url_for('logout') }}" style="color:#EF4444">🚪 Uitloggen</a>
  </nav>
</div>
<div class="main" style="display:flex;flex-direction:column;height:calc(100vh - 60px);overflow:hidden">
  <div style="padding:8px 12px;display:flex;flex-wrap:wrap;gap:6px">
    <button onclick="ask('Wat zijn de BTW tarieven voor mijn diensten?')" style="background:#fff;border:1px solid #E5E7EB;border-radius:16px;padding:5px 10px;font-size:12px;cursor:pointer;white-space:nowrap">BTW tarieven</button>
    <button onclick="ask('Hoe regel ik een modelovereenkomst?')" style="background:#fff;border:1px solid #E5E7EB;border-radius:16px;padding:5px 10px;font-size:12px;cursor:pointer;white-space:nowrap">Modelovereenkomst</button>
    <button onclick="ask('Wat mag ik afschrijven als ZZP\'er?')" style="background:#fff;border:1px solid #E5E7EB;border-radius:16px;padding:5px 10px;font-size:12px;cursor:pointer;white-space:nowrap">Afschrijven</button>
    <button onclick="ask('Moet ik een AOV verzekering afsluiten?')" style="background:#fff;border:1px solid #E5E7EB;border-radius:16px;padding:5px 10px;font-size:12px;cursor:pointer;white-space:nowrap">AOV verzekering</button>
    <button onclick="ask('Hoe werkt de MKB-winstvrijstelling?')" style="background:#fff;border:1px solid #E5E7EB;border-radius:16px;padding:5px 10px;font-size:12px;cursor:pointer;white-space:nowrap">MKB-winstvrijstelling</button>
    <button onclick="ask('Wat zijn de facturatie vereisten?')" style="background:#fff;border:1px solid #E5E7EB;border-radius:16px;padding:5px 10px;font-size:12px;cursor:pointer;white-space:nowrap">Facturatie vereisten</button>
  </div>
  <div id="chatMessages" style="flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px;font-size:13px">
    <div style="text-align:center;color:#868E96;padding:20px 0;font-size:12px">Stel een vraag over ZZP en ondernemerschap.</div>
  </div>
  <div style="border-top:1px solid #E5E7EB;padding:8px;display:flex;gap:8px">
    <input type="text" id="chatInput" placeholder="Vraag iets over ZZP..." style="flex:1;border:1px solid #E5E7EB;border-radius:8px;padding:8px 12px;font-size:13px;outline:none" onkeydown="if(event.key==='Enter')sendChat()">
    <button onclick="sendChat()" style="background:#003366;border:none;color:#fff;border-radius:8px;padding:8px 16px;cursor:pointer;font-size:13px">➤</button>
  </div>
</div>
<script>
function loadHistory(){
  try{var h=JSON.parse(localStorage.getItem('zzp_chat')||'[]');var box=document.getElementById('chatMessages');box.innerHTML='';for(var i=0;i<h.length;i++){var m=h[i];if(m.role==='user'){box.innerHTML+='<div style="align-self:flex-end;background:#003366;color:#fff;padding:8px 12px;border-radius:12px 12px 2px 12px;max-width:80%;white-space:pre-wrap">'+m.content.replace(/</g,'&lt;')+'</div>';}else{box.innerHTML+='<div style="align-self:flex-start;background:#F1F3F5;color:#333;padding:8px 12px;border-radius:12px 12px 12px 2px;max-width:85%;white-space:pre-wrap">'+m.content.replace(/</g,'&lt;')+'</div>';}}box.scrollTop=box.scrollHeight;}catch(e){}
}
function saveHistory(role,content){
  var h=JSON.parse(localStorage.getItem('zzp_chat')||'[]');h.push({role:role,content:content});localStorage.setItem('zzp_chat',JSON.stringify(h));
}
function clearChat(){if(confirm('Chatgeschiedenis wissen?')){localStorage.removeItem('zzp_chat');location.reload();}}
function ask(q){document.getElementById('chatInput').value=q;sendChat();}
function sendChat(){
  var input=document.getElementById('chatInput');var msg=input.value.trim();if(!msg)return;input.value='';
  var box=document.getElementById('chatMessages');
  box.innerHTML+='<div style="align-self:flex-end;background:#003366;color:#fff;padding:8px 12px;border-radius:12px 12px 2px 12px;max-width:80%;white-space:pre-wrap">'+msg.replace(/</g,'&lt;')+'</div>';
  saveHistory('user',msg);
  box.innerHTML+='<div id="chatLoading" style="align-self:flex-start;color:#868E96;font-size:12px;padding:4px 0">Typend...</div>';
  box.scrollTop=box.scrollHeight;
  fetch('/zzp/api/chat',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:msg})})
  .then(function(r){return r.json();}).then(function(d){
    var ld=document.getElementById('chatLoading');if(ld)ld.remove();
    var reply=d.reply||'Geen antwoord';
    box.innerHTML+='<div style="align-self:flex-start;background:#F1F3F5;color:#333;padding:8px 12px;border-radius:12px 12px 12px 2px;max-width:85%;white-space:pre-wrap">'+reply.replace(/</g,'&lt;')+'</div>';
    saveHistory('assistant',reply);
    box.scrollTop=box.scrollHeight;
  }).catch(function(e){var ld=document.getElementById('chatLoading');if(ld)ld.remove();box.innerHTML+='<div style="color:#EF4444">Fout: '+e+'</div>';box.scrollTop=box.scrollHeight;});
}
loadHistory();
</script>
{% endblock %}
""")

@app.route('/zzp/advisor')
@login_required
def zzp_advisor():
    return render_template_string(ADVISOR_TMPL)

@app.route('/zzp/api/chat', methods=['POST'])
@login_required
def zzp_chat():
    data = request.get_json()
    user_msg = data.get('message','').strip()
    if not user_msg:
        return jsonify({'error':'Leeg bericht'}), 400
    messages = [{"role":"system","content":ZZP_SYSTEM}]
    # Tavily crosscheck for legal/regulatory questions
    tavily_ctx = ''
    if TAVILY_KEY and any(w in user_msg.lower() for w in ['wetgeving','belasting','btw','kvk','dba','var','pensioen','aov','controle','facturatie','aftrek','vrijstelling','tarief']):
        try:
            tp = json.dumps({"query":user_msg+" Nederland 2024 2025","max_results":3,"search_depth":"basic","api_key":TAVILY_KEY}).encode()
            tr = urllib.request.Request("https://api.tavily.com/search",data=tp,headers={"Content-Type":"application/json"})
            tresp = urllib.request.urlopen(tr,timeout=10)
            tdata = json.loads(tresp.read())
            if tdata.get('results'):
                tavily_ctx = '\n\nActuele informatie:\n'+'\n'.join(f"- {r.get('content','')[:200]}" for r in tdata['results'][:3])
        except Exception as e:
            print(f'[ZZP Tavily] failed: {e}')
    if tavily_ctx:
        messages.append({"role":"system","content":"Gebruik deze actuele informatie ter aanvulling:"+tavily_ctx})
    messages.append({"role":"user","content":user_msg})
    try:
        reply = ai_complete(messages)
        return jsonify({'reply':reply})
    except Exception as e:
        print(f'[ZZP Chat] Error: {e}')
        return jsonify({'reply':'⚠️ De AI is momenteel overbelast. Probeer het over een minuut opnieuw.'})

if __name__ == '__main__':
    print("=" * 50)
    print("ZZP Dashboard running on http://127.0.0.1:5060/")
    print("=" * 50)
    app.run(host='0.0.0.0', port=5065, debug=False)
