"""routes/admin.py — admin panel: products, ingredients, users, outlets, roles."""
import sys, json, time, hashlib, hmac
from db import (app, q, run, get_db, today, now, _log_action, _int, _float, _str,
                csrf_protect, MANAGER_ROLES, ALL_ROLES, MPESA_SECRET,
                _client_ip, _get_csrf_token, hash_pw, check_pw)
from auth import login_required, role_required, is_manager, is_gm, current_user
from services import get_cash_position, get_outlet_low_stock, _build_reconciliation, calc_expected_revenue, cost_per_unit, calc_payroll, calc_ingredient_cost
from flask import render_template, request, redirect, url_for, session, jsonify, flash

@app.route('/admin')
@login_required
@role_required('general_manager','manager')
def admin():
    user    = current_user()
    role    = session.get('role')
    outlets = [dict(r) for r in q("SELECT * FROM outlets WHERE active=1")]
    cashiers = q("SELECT id,name FROM users WHERE role='cashier' AND active=1 ORDER BY name")
    waiters  = q("SELECT id,name FROM users WHERE role='waiter' AND active=1 ORDER BY name")
    d = today()
    assignments = q("""SELECT oa.*, u.name as cashier_name, o.name as outlet_name
                       FROM outlet_assignments oa
                       JOIN users u ON oa.cashier_id=u.id
                       JOIN outlets o ON oa.outlet_id=o.id
                       WHERE oa.date=? ORDER BY o.name""", (d,))
    return render_template('admin.html', user=user, role=role,
                           outlets=outlets, cashiers=cashiers, waiters=waiters,
                           assignments=assignments, today=d)

@app.route('/api/products', methods=['GET','POST'])
@login_required
@csrf_protect
def api_products():
    if request.method == 'POST':
        if session.get('role') not in MANAGER_ROLES: return jsonify({'error':'Unauthorized'}),403
        d = request.get_json()
        if not d.get('name') or not d.get('price'): return jsonify({'error':'name and price required'}),400
        pid = run("INSERT INTO products (name,category,unit,price) VALUES (?,?,?,?)",
                  (_str(d['name']),_str(d['category']),_str(d.get('unit','portion'),20),_float(d['price'])))
        return jsonify({'ok':True,'id':pid})
    products = q("""SELECT p.*, COALESCE(cpu.cost,0) as cost_per_unit
                    FROM products p
                    LEFT JOIN (
                        SELECT product_id, SUM((qty_used/yields)*cost_per_unit) as cost
                        FROM recipes r JOIN ingredients i ON r.ingredient_id=i.id
                        GROUP BY product_id
                    ) cpu ON p.id=cpu.product_id
                    WHERE p.active=1 ORDER BY p.category,p.name""")
    return jsonify([dict(p) for p in products])

@app.route('/api/products/<int:pid>', methods=['PUT','DELETE'])
@login_required
@role_required(*MANAGER_ROLES)
@csrf_protect
def api_product(pid):
    if request.method == 'DELETE':
        if session.get('role') != 'general_manager': return jsonify({'error':'Only GM can delete'}),403
        run("UPDATE products SET active=0 WHERE id=?",(pid,))
        return jsonify({'ok':True})
    d = request.get_json()
    run("UPDATE products SET name=?,category=?,unit=?,price=? WHERE id=?",
        (_str(d['name']),_str(d['category']),_str(d.get('unit','portion'),20),_float(d['price']),pid))
    return jsonify({'ok':True})

@app.route('/api/ingredients', methods=['GET','POST'])
@login_required
@csrf_protect
def api_ingredients():
    if request.method == 'POST':
        if session.get('role') not in MANAGER_ROLES: return jsonify({'error':'Unauthorized'}),403
        d   = request.get_json()
        iid = run("INSERT INTO ingredients (name,unit,cost_per_unit,reorder_level,category) VALUES (?,?,?,?,?)",
                  (_str(d['name']),_str(d['unit'],30),_float(d['cost']),_float(d.get('reorder_level',5)),_str(d.get('category','ingredient'),30)))
        run("INSERT INTO stock (ingredient_id,quantity) VALUES (?,?)",(iid,0))
        return jsonify({'ok':True,'id':iid})
    ings = q("""SELECT i.*, COALESCE(s.quantity,0) as stock
                FROM ingredients i LEFT JOIN stock s ON i.id=s.ingredient_id
                ORDER BY i.category,i.name""")
    return jsonify([dict(i) for i in ings])

@app.route('/api/ingredients/<int:iid>', methods=['PUT','DELETE'])
@login_required
@role_required(*MANAGER_ROLES)
@csrf_protect
def api_ingredient(iid):
    if request.method == 'DELETE':
        if session.get('role') != 'general_manager': return jsonify({'error':'Only GM can delete'}),403
        run("DELETE FROM recipes WHERE ingredient_id=?",(iid,))
        run("DELETE FROM stock WHERE ingredient_id=?",(iid,))
        run("DELETE FROM ingredients WHERE id=?",(iid,))
        return jsonify({'ok':True})
    d = request.get_json()
    run("UPDATE ingredients SET name=?,unit=?,cost_per_unit=?,reorder_level=?,category=? WHERE id=?",
        (_str(d['name']),_str(d['unit'],30),_float(d['cost']),_float(d.get('reorder_level',5)),_str(d.get('category','ingredient'),30),iid))
    return jsonify({'ok':True})

@app.route('/api/recipes/<int:product_id>', methods=['GET','POST','DELETE'])
@login_required
@csrf_protect
def api_recipes(product_id):
    if request.method == 'POST':
        if session.get('role') not in MANAGER_ROLES: return jsonify({'error':'Unauthorized'}),403
        d = request.get_json()
        run("DELETE FROM recipes WHERE product_id=? AND ingredient_id=?",(product_id,d['ingredient_id']))
        rid = run("INSERT INTO recipes (product_id,ingredient_id,qty_used,yields,note) VALUES (?,?,?,?,?)",
                  (product_id,d['ingredient_id'],_float(d['qty_used']),max(1,_int(d['yields'])),_str(d.get('note',''),100)))
        return jsonify({'ok':True,'id':rid})
    if request.method == 'DELETE':
        if session.get('role') != 'general_manager': return jsonify({'error':'Only GM can delete'}),403
        rid = request.args.get('recipe_id')
        run("DELETE FROM recipes WHERE id=?",(rid,))
        return jsonify({'ok':True})
    recipe = q("""SELECT r.*, i.name as ing_name, i.unit, i.cost_per_unit
                  FROM recipes r JOIN ingredients i ON r.ingredient_id=i.id
                  WHERE r.product_id=?""",(product_id,))
    return jsonify([dict(r) for r in recipe])

@app.route('/api/users', methods=['GET','POST'])
@login_required
@role_required(*MANAGER_ROLES)
@csrf_protect
def api_users():
    if request.method == 'POST':
        d   = request.get_json() or {}
        pw  = d.get('password', '')
        if not pw:
            return jsonify({'error': 'Password is required when creating a user'}), 400
        if len(pw) < 8:
            return jsonify({'error': 'Password must be at least 8 characters'}), 400
        uid = run("INSERT INTO users (name,email,password,role,line,outlet_id,pay_period,pay_amount) VALUES (?,?,?,?,?,?,?,?)",
                  (_str(d['name']),_str(d['email']),hash_pw(pw),
                   _str(d['role'],30),d.get('line'),d.get('outlet_id'),_str(d.get('pay_period','monthly'),20),_float(d.get('pay_amount',0))))
        _log_action('user_created', 'users', uid, new_value={'name': _str(d['name']), 'role': _str(d['role'],30)})
        return jsonify({'ok':True,'id':uid})
    users = q("""SELECT u.id, u.name, u.email, u.role, u.line, u.outlet_id,
                        u.active, u.created_at, o.name as outlet_name
                 FROM users u
                 LEFT JOIN outlets o ON u.outlet_id=o.id
                 WHERE u.active=1 ORDER BY u.role,u.name""")
    rows = [dict(u) for u in users]
    # Salary fields are only returned to general_manager / manager
    if session.get('role') not in MANAGER_ROLES:
        for r in rows:
            r.pop('pay_amount', None)
            r.pop('pay_period', None)
    return jsonify(rows)

@app.route('/api/users/<int:uid>', methods=['PUT','DELETE'])
@login_required
@role_required(*MANAGER_ROLES)
@csrf_protect
def api_user(uid):
    if request.method == 'DELETE':
        if session.get('role') != 'general_manager': return jsonify({'error':'Only GM can delete'}),403
        old = q("SELECT name, role FROM users WHERE id=?", (uid,), one=True)
        run("UPDATE users SET active=0 WHERE id=?",(uid,))
        _log_action('user_deactivated', 'users', uid, old_value=dict(old) if old else None)
        return jsonify({'ok':True})
    d = request.get_json()
    if d.get('password'):
        if len(d['password']) < 8:
            return jsonify({'error': 'Password must be at least 8 characters'}), 400
        run("UPDATE users SET name=?,email=?,password=?,role=?,line=?,outlet_id=?,pay_period=?,pay_amount=? WHERE id=?",
            (_str(d['name']),_str(d['email']),hash_pw(d['password']),_str(d['role'],30),d.get('line'),d.get('outlet_id'),
             _str(d.get('pay_period','monthly'),20),_float(d.get('pay_amount',0)),uid))
    else:
        run("UPDATE users SET name=?,email=?,role=?,line=?,outlet_id=?,pay_period=?,pay_amount=? WHERE id=?",
            (_str(d['name']),_str(d['email']),_str(d['role'],30),d.get('line'),d.get('outlet_id'),
             _str(d.get('pay_period','monthly'),20),_float(d.get('pay_amount',0)),uid))
    return jsonify({'ok':True})

@app.route('/api/outlets', methods=['GET','POST'])
@login_required
@csrf_protect
def api_outlets():
    if request.method == 'POST':
        if session.get('role') not in MANAGER_ROLES: return jsonify({'error':'Unauthorized'}),403
        d   = request.get_json()
        oid = run("INSERT INTO outlets (name,location,till_number) VALUES (?,?,?)",
                  (_str(d['name']),_str(d.get('location','')),_str(d.get('till_number',''),30)))
        return jsonify({'ok':True,'id':oid})
    outlets = [dict(r) for r in q("SELECT * FROM outlets WHERE active=1")]
    return jsonify([dict(o) for o in outlets])

@app.route('/api/outlets/<int:oid>', methods=['PUT','DELETE'])
@login_required
@role_required(*MANAGER_ROLES)
@csrf_protect
def api_outlet(oid):
    if request.method == 'DELETE':
        if session.get('role') != 'general_manager': return jsonify({'error':'Only GM can delete'}),403
        run("UPDATE outlets SET active=0 WHERE id=?",(oid,))
        return jsonify({'ok':True})
    d = request.get_json()
    run("UPDATE outlets SET name=?,location=?,till_number=? WHERE id=?",
        (_str(d['name']),_str(d.get('location','')),_str(d.get('till_number',''),30),oid))
    return jsonify({'ok':True})

