#!/usr/bin/env python3
"""
Vestjydsk Beslag A/S — Website
================================
Flask application with:
- Multilingual product catalogue (DA/EN/DE)
- Print-friendly product sheets
- Admin panel with login authentication
- CRUD for products and filter management
- Error handling throughout

Author: Vestjydsk Beslag A/S
"""

import json
import os
import functools
from flask import (
    Flask, render_template, request, redirect, url_for,
    jsonify, send_from_directory, session, abort
)

# ── Configuration ──────────────────────────────────────────────────────────────

app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'vb-secret-key-change-in-production')

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
PRODUCTS_FILE = os.path.join(BASE_DIR, 'data', 'products.json')
TRANSLATIONS_FILE = os.path.join(BASE_DIR, 'translations', 'translations.json')
SUPPORTED_LANGS = ['da', 'en', 'de']
DEFAULT_LANG = 'da'

# Hardcoded admin credentials — change these or move to environment variables
ADMIN_USERNAME = 'admin'
ADMIN_PASSWORD = 'VBadmin2026'

# ── Data Loading ───────────────────────────────────────────────────────────────

def load_json(filepath):
    """Load and parse a JSON file. Returns empty dict on error."""
    try:
        with open(filepath, 'r', encoding='utf-8') as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError) as e:
        app.logger.error(f"Failed to load {filepath}: {e}")
        return {}

def save_json(filepath, data):
    """Save data to JSON file with error handling."""
    try:
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        return True
    except (IOError, TypeError) as e:
        app.logger.error(f"Failed to save {filepath}: {e}")
        return False

# Load data into memory at startup
PRODUCTS_DATA = load_json(PRODUCTS_FILE)
TRANSLATIONS = load_json(TRANSLATIONS_FILE)

# ── Helper Functions ───────────────────────────────────────────────────────────

def get_lang():
    """Get current language from URL parameter, defaulting to Danish."""
    lang = request.args.get('lang', DEFAULT_LANG)
    return lang if lang in SUPPORTED_LANGS else DEFAULT_LANG

def t(key, lang=None):
    """Get translation string by key and language."""
    if lang is None:
        lang = get_lang()
    return TRANSLATIONS.get(lang, TRANSLATIONS.get(DEFAULT_LANG, {})).get(key, key)

def require_admin(f):
    """Decorator: require admin login for a route."""
    @functools.wraps(f)
    def decorated(*args, **kwargs):
        if not session.get('admin_logged_in'):
            return redirect(url_for('admin_login'))
        return f(*args, **kwargs)
    return decorated

def find_product(item_no):
    """Find a product by item number. Returns (index, product) or (None, None)."""
    for i, p in enumerate(PRODUCTS_DATA.get('products', [])):
        if p['item_no'] == item_no:
            return i, p
    return None, None

# ── Template Context ───────────────────────────────────────────────────────────

@app.context_processor
def inject_globals():
    """Inject common variables into all templates."""
    lang = get_lang()
    return {
        'lang': lang,
        't': lambda key: t(key, lang),
        'supported_langs': SUPPORTED_LANGS,
        'current_url': request.path,
    }

# ── Error Handlers ─────────────────────────────────────────────────────────────

@app.errorhandler(404)
def page_not_found(e):
    """Handle 404 errors with a friendly page."""
    return render_template('error.html', code=404, message="Siden blev ikke fundet"), 404

@app.errorhandler(500)
def internal_error(e):
    """Handle 500 errors."""
    return render_template('error.html', code=500, message="Der opstod en intern fejl"), 500

# ── Public Routes ──────────────────────────────────────────────────────────────

@app.route('/')
def index():
    """Homepage with hero, news ticker, and USPs."""
    return render_template('index.html')

@app.route('/produkter')
@app.route('/products')
@app.route('/produkte')
def products():
    """Product catalogue with filters and search."""
    return render_template('products.html',
                           categories=PRODUCTS_DATA.get('categories', []),
                           material_labels=PRODUCTS_DATA.get('material_labels', {}),
                           type_labels=PRODUCTS_DATA.get('type_labels', {}))

@app.route('/print/<item_no>')
def print_product(item_no):
    """Print-friendly product sheet for a single product."""
    _, product = find_product(item_no)
    if product is None:
        abort(404)
    lang = get_lang()
    # Resolve labels for display
    cat_name = item_no  # fallback
    for c in PRODUCTS_DATA.get('categories', []):
        if c['id'] == product['category']:
            cat_name = c['name'].get(lang, c['name'].get('da', product['category']))
            break
    mat_label = PRODUCTS_DATA.get('material_labels', {}).get(
        product['material'], {}
    ).get(lang, product['material'])
    type_label = PRODUCTS_DATA.get('type_labels', {}).get(
        product['type'], {}
    ).get(lang, product.get('type', ''))

    return render_template('print.html',
                           product=product,
                           cat_name=cat_name,
                           mat_label=mat_label,
                           type_label=type_label)

@app.route('/galleri')
@app.route('/gallery')
@app.route('/galerie')
def gallery():
    """Photo gallery with lightbox."""
    lang = get_lang()
    gallery_items = []
    for item in PRODUCTS_DATA.get('gallery', []):
        gallery_items.append({
            'filename': item['filename'],
            'caption': item['caption'].get(lang, item['caption'].get('da', ''))
        })
    return render_template('gallery.html', gallery_items=gallery_items)

@app.route('/kontakt')
@app.route('/contact')
@app.route('/kontaktieren')
def contact():
    """Contact page with company information."""
    return render_template('contact.html')

# ── API Routes ─────────────────────────────────────────────────────────────────

@app.route('/api/products')
def api_products():
    """Public API: Get products with optional category/search filter."""
    lang = get_lang()
    category = request.args.get('category', '').strip()
    search = request.args.get('search', '').lower().strip()

    prods = PRODUCTS_DATA.get('products', [])
    if category:
        prods = [p for p in prods if p.get('category') == category]
    if search:
        prods = [p for p in prods if
                 search in p.get('item_no', '').lower() or
                 search in p.get('name', {}).get(lang, '').lower()]

    result = []
    for p in prods:
        result.append({
            'item_no': p.get('item_no', ''),
            'name': p.get('name', {}).get(lang, p.get('name', {}).get('da', '')),
            'category': p.get('category', ''),
            'size': p.get('size', ''),
            'material': p.get('material', ''),
            'type': p.get('type', ''),
            'image': f"/static/images/products/{p.get('item_no', '')}.jpeg"
        })
    return jsonify(result)

@app.route('/api/categories')
def api_categories():
    """Public API: Get all categories."""
    lang = get_lang()
    result = []
    for c in PRODUCTS_DATA.get('categories', []):
        result.append({
            'id': c['id'],
            'name': c['name'].get(lang, c['name'].get('da', '')),
            'group': c.get('group', ''),
            'filters': c.get('filters', {})
        })
    return jsonify(result)

# ── Static File Serving ────────────────────────────────────────────────────────

@app.route('/static/images/products/<filename>')
def product_image(filename):
    """Serve product images with placeholder fallback."""
    img_dir = os.path.join(BASE_DIR, 'static', 'images', 'products')
    filepath = os.path.join(img_dir, filename)
    if os.path.exists(filepath):
        return send_from_directory(img_dir, filename)
    # Return placeholder SVG for missing images
    placeholder_dir = os.path.join(BASE_DIR, 'static', 'images')
    return send_from_directory(placeholder_dir, 'placeholder.svg')

# ── Admin Authentication ───────────────────────────────────────────────────────

@app.route('/admin/login', methods=['GET', 'POST'])
def admin_login():
    """Admin login page with hardcoded credentials."""
    error = None
    if request.method == 'POST':
        username = request.form.get('username', '').strip()
        password = request.form.get('password', '')
        if username == ADMIN_USERNAME and password == ADMIN_PASSWORD:
            session['admin_logged_in'] = True
            return redirect(url_for('admin'))
        else:
            error = 'Forkert brugernavn eller adgangskode'
    return render_template('admin_login.html', error=error)

@app.route('/admin/logout')
def admin_logout():
    """Log out of admin panel."""
    session.pop('admin_logged_in', None)
    return redirect(url_for('index'))

# ── Admin Panel ────────────────────────────────────────────────────────────────

@app.route('/admin')
@require_admin
def admin():
    """Admin dashboard for managing products and filters."""
    return render_template('admin.html',
                           products=PRODUCTS_DATA.get('products', []),
                           categories=PRODUCTS_DATA.get('categories', []),
                           material_labels=PRODUCTS_DATA.get('material_labels', {}),
                           type_labels=PRODUCTS_DATA.get('type_labels', {}))

# ── Admin Product API ──────────────────────────────────────────────────────────

@app.route('/api/admin/products', methods=['GET'])
@require_admin
def admin_get_products():
    """Get all products (admin)."""
    return jsonify(PRODUCTS_DATA.get('products', []))

@app.route('/api/admin/products', methods=['POST'])
@require_admin
def admin_add_product():
    """Add a new product."""
    data = request.get_json()
    if not data:
        return jsonify({'error': 'Ingen data modtaget'}), 400
    item_no = data.get('item_no', '').strip()
    if not item_no:
        return jsonify({'error': 'Varenummer er påkrævet'}), 400
    if not data.get('name_da', '').strip():
        return jsonify({'error': 'Dansk produktnavn er påkrævet'}), 400

    # Check for duplicates
    existing, _ = find_product(item_no)
    if existing is not None:
        return jsonify({'error': f'Varenummer {item_no} findes allerede'}), 400

    product = {
        'item_no': item_no,
        'category': data.get('category', ''),
        'size': data.get('size', '').strip(),
        'material': data.get('material', ''),
        'type': data.get('type', ''),
        'name': {
            'da': data.get('name_da', '').strip(),
            'en': data.get('name_en', '').strip(),
            'de': data.get('name_de', '').strip()
        }
    }
    PRODUCTS_DATA.setdefault('products', []).append(product)
    if not save_json(PRODUCTS_FILE, PRODUCTS_DATA):
        return jsonify({'error': 'Kunne ikke gemme til fil'}), 500
    return jsonify({'success': True, 'product': product})

@app.route('/api/admin/products/<item_no>', methods=['PUT'])
@require_admin
def admin_update_product(item_no):
    """Update an existing product."""
    data = request.get_json()
    if not data:
        return jsonify({'error': 'Ingen data modtaget'}), 400

    idx, product = find_product(item_no)
    if idx is None:
        return jsonify({'error': 'Produkt ikke fundet'}), 404

    PRODUCTS_DATA['products'][idx] = {
        'item_no': data.get('item_no', item_no).strip(),
        'category': data.get('category', product['category']),
        'size': data.get('size', product['size']).strip(),
        'material': data.get('material', product['material']),
        'type': data.get('type', product['type']),
        'name': {
            'da': data.get('name_da', product['name'].get('da', '')).strip(),
            'en': data.get('name_en', product['name'].get('en', '')).strip(),
            'de': data.get('name_de', product['name'].get('de', '')).strip()
        }
    }
    if not save_json(PRODUCTS_FILE, PRODUCTS_DATA):
        return jsonify({'error': 'Kunne ikke gemme til fil'}), 500
    return jsonify({'success': True, 'product': PRODUCTS_DATA['products'][idx]})

@app.route('/api/admin/products/<item_no>', methods=['DELETE'])
@require_admin
def admin_delete_product(item_no):
    """Delete a product by item number."""
    idx, _ = find_product(item_no)
    if idx is None:
        return jsonify({'error': 'Produkt ikke fundet'}), 404
    PRODUCTS_DATA['products'].pop(idx)
    if not save_json(PRODUCTS_FILE, PRODUCTS_DATA):
        return jsonify({'error': 'Kunne ikke gemme til fil'}), 500
    return jsonify({'success': True})

# ── Admin Filter Management API ────────────────────────────────────────────────

@app.route('/api/admin/filters', methods=['GET'])
@require_admin
def admin_get_filters():
    """Get all filter data (categories, materials, types)."""
    return jsonify({
        'categories': PRODUCTS_DATA.get('categories', []),
        'material_labels': PRODUCTS_DATA.get('material_labels', {}),
        'type_labels': PRODUCTS_DATA.get('type_labels', {})
    })

@app.route('/api/admin/materials', methods=['POST'])
@require_admin
def admin_add_material():
    """Add a new material label."""
    data = request.get_json()
    key = data.get('key', '').strip()
    if not key:
        return jsonify({'error': 'Materialnøgle er påkrævet'}), 400
    if key in PRODUCTS_DATA.get('material_labels', {}):
        return jsonify({'error': f'Materiale "{key}" findes allerede'}), 400
    PRODUCTS_DATA.setdefault('material_labels', {})[key] = {
        'da': data.get('da', '').strip(),
        'en': data.get('en', '').strip(),
        'de': data.get('de', '').strip()
    }
    if not save_json(PRODUCTS_FILE, PRODUCTS_DATA):
        return jsonify({'error': 'Kunne ikke gemme'}), 500
    return jsonify({'success': True})

@app.route('/api/admin/materials/<key>', methods=['PUT'])
@require_admin
def admin_update_material(key):
    """Update a material label."""
    data = request.get_json()
    if key not in PRODUCTS_DATA.get('material_labels', {}):
        return jsonify({'error': 'Materiale ikke fundet'}), 404
    PRODUCTS_DATA['material_labels'][key] = {
        'da': data.get('da', '').strip(),
        'en': data.get('en', '').strip(),
        'de': data.get('de', '').strip()
    }
    if not save_json(PRODUCTS_FILE, PRODUCTS_DATA):
        return jsonify({'error': 'Kunne ikke gemme'}), 500
    return jsonify({'success': True})

@app.route('/api/admin/materials/<key>', methods=['DELETE'])
@require_admin
def admin_delete_material(key):
    """Delete a material label (only if not in use)."""
    if key not in PRODUCTS_DATA.get('material_labels', {}):
        return jsonify({'error': 'Materiale ikke fundet'}), 404
    # Check if any products use this material
    in_use = any(p.get('material') == key for p in PRODUCTS_DATA.get('products', []))
    if in_use:
        return jsonify({'error': f'Kan ikke slette — materiale bruges af produkter'}), 400
    del PRODUCTS_DATA['material_labels'][key]
    if not save_json(PRODUCTS_FILE, PRODUCTS_DATA):
        return jsonify({'error': 'Kunne ikke gemme'}), 500
    return jsonify({'success': True})

@app.route('/api/admin/types', methods=['POST'])
@require_admin
def admin_add_type():
    """Add a new type label."""
    data = request.get_json()
    key = data.get('key', '').strip()
    if not key:
        return jsonify({'error': 'Typenøgle er påkrævet'}), 400
    if key in PRODUCTS_DATA.get('type_labels', {}):
        return jsonify({'error': f'Type "{key}" findes allerede'}), 400
    PRODUCTS_DATA.setdefault('type_labels', {})[key] = {
        'da': data.get('da', '').strip(),
        'en': data.get('en', '').strip(),
        'de': data.get('de', '').strip()
    }
    if not save_json(PRODUCTS_FILE, PRODUCTS_DATA):
        return jsonify({'error': 'Kunne ikke gemme'}), 500
    return jsonify({'success': True})

@app.route('/api/admin/types/<key>', methods=['DELETE'])
@require_admin
def admin_delete_type(key):
    """Delete a type label (only if not in use)."""
    if key not in PRODUCTS_DATA.get('type_labels', {}):
        return jsonify({'error': 'Type ikke fundet'}), 404
    in_use = any(p.get('type') == key for p in PRODUCTS_DATA.get('products', []))
    if in_use:
        return jsonify({'error': 'Kan ikke slette — type bruges af produkter'}), 400
    del PRODUCTS_DATA['type_labels'][key]
    if not save_json(PRODUCTS_FILE, PRODUCTS_DATA):
        return jsonify({'error': 'Kunne ikke gemme'}), 500
    return jsonify({'success': True})

# ── Main ───────────────────────────────────────────────────────────────────────

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)
