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

import os, sqlite3, hashlib, secrets, json
from datetime import datetime, timedelta
from functools import wraps
from flask import Flask, request, session, redirect, url_for, render_template_string, flash, g
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
    );
    """)
    # 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', '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}
.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('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}">🚪 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-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('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}">🚪 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('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}">🚪 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('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}">🚪 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('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}">🚪 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('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}">🚪 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('settings_page') }}">⚙️ Instellingen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}">🚪 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('settings_page') }}">⚙️ Instellingen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}">🚪 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('btw') }}" class="active">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}">⚙️ Instellingen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}">🚪 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('btw') }}">📋 BTW-overzicht</a>
    <a href="{{ url_for('settings_page') }}" class="active">⚙️ Instellingen</a>
  </nav>
  <div class="logout"><a href="{{ url_for('logout') }}">🚪 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>
  </div>
  <button class="btn btn-primary" style="margin-top:8px">Opslaan</button>
  </form>
</div>
{% 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']})

    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)
    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'))

# ── 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']

@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()

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)
