# /home/Autopartes/pos/blueprints/fleet_bp.py
"""Fleet management blueprint: vehicles, maintenance schedules, logs, alerts."""

from datetime import datetime, timedelta
from flask import Blueprint, request, jsonify, g
from middleware import require_auth
from tenant_db import get_tenant_conn
from services.audit import log_action

fleet_bp = Blueprint('fleet', __name__, url_prefix='/pos/api/fleet')


# ─── Vehicles CRUD ─────────────────────────────

@fleet_bp.route('/vehicles', methods=['GET'])
@require_auth('fleet.view')
def list_vehicles():
    """List fleet vehicles with pagination and search.

    Query params:
        q: search string (matches plate, make, model, owner_name)
        page: page number (default 1)
        per_page: items per page (default 50, max 200)
        active_only: filter active only (default true)
    """
    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    page = int(request.args.get('page', 1))
    per_page = min(int(request.args.get('per_page', 50)), 200)
    search = request.args.get('q', '').strip()
    active_only = request.args.get('active_only', 'true').lower() != 'false'

    where_clauses = []
    params = []

    if active_only:
        where_clauses.append("v.is_active = true")
    if g.branch_id:
        where_clauses.append("v.branch_id = %s")
        params.append(g.branch_id)
    if search:
        where_clauses.append(
            "(v.plate ILIKE %s OR v.make ILIKE %s OR v.model ILIKE %s OR v.owner_name ILIKE %s OR v.vin ILIKE %s)"
        )
        params.extend([f'%{search}%'] * 5)

    where = " AND ".join(where_clauses) if where_clauses else "true"

    # Count
    cur.execute(f"SELECT count(*) FROM fleet_vehicles v WHERE {where}", params)
    total = cur.fetchone()[0]

    # Fetch
    cur.execute(f"""
        SELECT v.id, v.branch_id, v.plate, v.vin, v.make, v.model, v.year,
               v.current_mileage, v.fuel_type, v.color, v.owner_name,
               v.notes, v.is_active, v.created_at
        FROM fleet_vehicles v
        WHERE {where}
        ORDER BY v.created_at DESC
        LIMIT %s OFFSET %s
    """, params + [per_page, (page - 1) * per_page])

    vehicles = []
    for r in cur.fetchall():
        vehicles.append({
            'id': r[0], 'branch_id': r[1], 'plate': r[2], 'vin': r[3],
            'make': r[4], 'model': r[5], 'year': r[6],
            'current_mileage': r[7], 'fuel_type': r[8], 'color': r[9],
            'owner_name': r[10], 'notes': r[11], 'is_active': r[12],
            'created_at': str(r[13]) if r[13] else None,
        })

    cur.close()
    conn.close()

    total_pages = (total + per_page - 1) // per_page
    return jsonify({
        'data': vehicles,
        'pagination': {'page': page, 'per_page': per_page, 'total': total, 'total_pages': total_pages}
    })


@fleet_bp.route('/vehicles/<int:vehicle_id>', methods=['GET'])
@require_auth('fleet.view')
def get_vehicle(vehicle_id):
    """Vehicle detail with maintenance schedules and recent logs."""
    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    cur.execute("""
        SELECT id, branch_id, plate, vin, make, model, year,
               current_mileage, fuel_type, color, owner_name,
               notes, is_active, created_at
        FROM fleet_vehicles WHERE id = %s
    """, (vehicle_id,))
    row = cur.fetchone()
    if not row:
        cur.close(); conn.close()
        return jsonify({'error': 'Vehicle not found'}), 404

    vehicle = {
        'id': row[0], 'branch_id': row[1], 'plate': row[2], 'vin': row[3],
        'make': row[4], 'model': row[5], 'year': row[6],
        'current_mileage': row[7], 'fuel_type': row[8], 'color': row[9],
        'owner_name': row[10], 'notes': row[11], 'is_active': row[12],
        'created_at': str(row[13]) if row[13] else None,
    }

    # Maintenance schedules
    cur.execute("""
        SELECT id, maintenance_type, interval_km, interval_months,
               last_done_at, last_done_km, next_due_at, next_due_km,
               notes, is_active
        FROM fleet_maintenance_schedules
        WHERE vehicle_id = %s AND is_active = true
        ORDER BY next_due_at NULLS LAST, next_due_km NULLS LAST
    """, (vehicle_id,))
    vehicle['schedules'] = []
    for r in cur.fetchall():
        vehicle['schedules'].append({
            'id': r[0], 'maintenance_type': r[1], 'interval_km': r[2],
            'interval_months': r[3],
            'last_done_at': str(r[4]) if r[4] else None,
            'last_done_km': r[5],
            'next_due_at': str(r[6]) if r[6] else None,
            'next_due_km': r[7],
            'notes': r[8], 'is_active': r[9],
        })

    # Recent logs (last 20)
    cur.execute("""
        SELECT l.id, l.schedule_id, l.maintenance_type, l.mileage_at,
               l.cost, l.parts_used, l.employee_id, l.notes, l.created_at,
               e.name as employee_name
        FROM fleet_maintenance_logs l
        LEFT JOIN employees e ON l.employee_id = e.id
        WHERE l.vehicle_id = %s
        ORDER BY l.created_at DESC
        LIMIT 20
    """, (vehicle_id,))
    vehicle['recent_logs'] = []
    for r in cur.fetchall():
        vehicle['recent_logs'].append({
            'id': r[0], 'schedule_id': r[1], 'maintenance_type': r[2],
            'mileage_at': r[3], 'cost': float(r[4]) if r[4] else 0,
            'parts_used': r[5], 'employee_id': r[6], 'notes': r[7],
            'created_at': str(r[8]) if r[8] else None,
            'employee_name': r[9],
        })

    cur.close()
    conn.close()
    return jsonify(vehicle)


@fleet_bp.route('/vehicles/schedules', methods=['GET'])
@require_auth('fleet.view')
def list_all_schedules():
    """Return all active maintenance schedules joined with vehicle data.

    Replaces the N+1 pattern of fetching schedules per vehicle.
    """
    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    where_clauses = ["v.is_active = true", "s.is_active = true"]
    params = []
    if g.branch_id:
        where_clauses.append("v.branch_id = %s")
        params.append(g.branch_id)

    vehicle_ids = request.args.get('vehicle_ids', '').strip()
    if vehicle_ids:
        ids = [int(x) for x in vehicle_ids.split(',') if x.strip().isdigit()]
        if ids:
            where_clauses.append("v.id = ANY(%s)")
            params.append(ids)

    where = " AND ".join(where_clauses)

    cur.execute(f"""
        SELECT s.id, s.vehicle_id, s.maintenance_type, s.interval_km,
               s.interval_months, s.last_done_at, s.last_done_km,
               s.next_due_at, s.next_due_km, s.notes,
               v.plate, v.make, v.model, v.current_mileage, v.color
        FROM fleet_maintenance_schedules s
        JOIN fleet_vehicles v ON v.id = s.vehicle_id
        WHERE {where}
        ORDER BY v.plate, s.next_due_at NULLS LAST, s.next_due_km NULLS LAST
    """, params)

    schedules = []
    for r in cur.fetchall():
        schedules.append({
            'id': r[0], 'vehicle_id': r[1], 'maintenance_type': r[2],
            'interval_km': r[3], 'interval_months': r[4],
            'last_done_at': str(r[5]) if r[5] else None, 'last_done_km': r[6],
            'next_due_at': str(r[7]) if r[7] else None, 'next_due_km': r[8],
            'notes': r[9],
            'vehicle': {
                'plate': r[10], 'make': r[11], 'model': r[12],
                'current_mileage': r[13], 'color': r[14]
            }
        })

    cur.close(); conn.close()
    return jsonify({'data': schedules})


@fleet_bp.route('/vehicles/history', methods=['GET'])
@require_auth('fleet.view')
def list_all_history():
    """Return recent maintenance logs for all vehicles joined with vehicle data.

    Replaces the N+1 pattern of fetching logs per vehicle.
    """
    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    limit = min(int(request.args.get('limit', 200)), 500)

    where_clauses = ["v.is_active = true"]
    params = [limit]
    if g.branch_id:
        where_clauses.append("v.branch_id = %s")
        params.append(g.branch_id)

    vehicle_ids = request.args.get('vehicle_ids', '').strip()
    if vehicle_ids:
        ids = [int(x) for x in vehicle_ids.split(',') if x.strip().isdigit()]
        if ids:
            where_clauses.append("v.id = ANY(%s)")
            params.append(ids)

    where = " AND ".join(where_clauses)

    cur.execute(f"""
        SELECT l.id, l.vehicle_id, l.schedule_id, l.maintenance_type,
               l.mileage_at, l.cost, l.parts_used, l.notes, l.created_at,
               e.name as employee_name,
               v.plate, v.make, v.model, v.color
        FROM fleet_maintenance_logs l
        JOIN fleet_vehicles v ON v.id = l.vehicle_id
        LEFT JOIN employees e ON l.employee_id = e.id
        WHERE {where}
        ORDER BY l.created_at DESC
        LIMIT %s
    """, params)

    logs = []
    for r in cur.fetchall():
        logs.append({
            'id': r[0], 'vehicle_id': r[1], 'schedule_id': r[2],
            'maintenance_type': r[3], 'mileage_at': r[4],
            'cost': float(r[5]) if r[5] else 0, 'parts_used': r[6],
            'notes': r[7], 'created_at': str(r[8]) if r[8] else None,
            'employee_name': r[9],
            'vehicle': {'plate': r[10], 'make': r[11], 'model': r[12], 'color': r[13]}
        })

    cur.close(); conn.close()
    return jsonify({'data': logs})


@fleet_bp.route('/vehicles', methods=['POST'])
@require_auth('fleet.create')
def create_vehicle():
    """Create a fleet vehicle.

    Body: {plate, vin, make, model, year, current_mileage, fuel_type, color, owner_name, notes}
    """
    data = request.get_json() or {}
    if not data.get('plate') and not data.get('vin'):
        return jsonify({'error': 'plate or vin is required'}), 400

    branch_id = data.get('branch_id', g.branch_id)

    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    try:
        cur.execute("""
            INSERT INTO fleet_vehicles
                (branch_id, plate, vin, make, model, year,
                 current_mileage, fuel_type, color, owner_name, notes)
            VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
            RETURNING id
        """, (
            branch_id, data.get('plate'), data.get('vin'),
            data.get('make'), data.get('model'), data.get('year'),
            data.get('current_mileage', 0), data.get('fuel_type', 'gasolina'),
            data.get('color'), data.get('owner_name'), data.get('notes'),
        ))
        vehicle_id = cur.fetchone()[0]

        log_action(conn, 'FLEET_VEHICLE_CREATE', 'fleet_vehicle', vehicle_id,
                   new_value={'plate': data.get('plate'), 'make': data.get('make'),
                              'model': data.get('model')})

        conn.commit()
        cur.close(); conn.close()
        return jsonify({'id': vehicle_id, 'message': 'Vehicle created'}), 201

    except Exception as e:
        conn.rollback()
        cur.close(); conn.close()
        return jsonify({'error': str(e)}), 500


@fleet_bp.route('/vehicles/<int:vehicle_id>', methods=['PUT'])
@require_auth('fleet.edit')
def update_vehicle(vehicle_id):
    """Update vehicle fields including mileage.

    Body: any subset of {plate, vin, make, model, year, current_mileage, fuel_type,
                         color, owner_name, notes, is_active}
    """
    data = request.get_json() or {}
    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    cur.execute("SELECT id FROM fleet_vehicles WHERE id = %s", (vehicle_id,))
    if not cur.fetchone():
        cur.close(); conn.close()
        return jsonify({'error': 'Vehicle not found'}), 404

    allowed = ['plate', 'vin', 'make', 'model', 'year', 'current_mileage',
               'fuel_type', 'color', 'owner_name', 'notes', 'is_active', 'branch_id']
    sets = []
    vals = []
    for field in allowed:
        if field in data:
            sets.append(f"{field} = %s")
            vals.append(data[field])

    if not sets:
        cur.close(); conn.close()
        return jsonify({'error': 'No fields to update'}), 400

    vals.append(vehicle_id)
    try:
        cur.execute(f"UPDATE fleet_vehicles SET {', '.join(sets)} WHERE id = %s", vals)
        log_action(conn, 'FLEET_VEHICLE_UPDATE', 'fleet_vehicle', vehicle_id,
                   new_value=data)
        conn.commit()
        cur.close(); conn.close()
        return jsonify({'message': 'Vehicle updated'})
    except Exception as e:
        conn.rollback()
        cur.close(); conn.close()
        return jsonify({'error': str(e)}), 500


@fleet_bp.route('/vehicles/<int:vehicle_id>', methods=['DELETE'])
@require_auth('fleet.delete')
def deactivate_vehicle(vehicle_id):
    """Soft-delete: set is_active = false."""
    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    cur.execute("SELECT id FROM fleet_vehicles WHERE id = %s", (vehicle_id,))
    if not cur.fetchone():
        cur.close(); conn.close()
        return jsonify({'error': 'Vehicle not found'}), 404

    cur.execute("UPDATE fleet_vehicles SET is_active = false WHERE id = %s", (vehicle_id,))
    log_action(conn, 'FLEET_VEHICLE_DEACTIVATE', 'fleet_vehicle', vehicle_id)
    conn.commit()
    cur.close(); conn.close()
    return jsonify({'message': 'Vehicle deactivated'})


# ─── Maintenance Schedules ─────────────────────────────

@fleet_bp.route('/vehicles/<int:vehicle_id>/schedules', methods=['GET'])
@require_auth('fleet.view')
def list_schedules(vehicle_id):
    """Maintenance schedules for a vehicle."""
    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    cur.execute("""
        SELECT id, maintenance_type, interval_km, interval_months,
               last_done_at, last_done_km, next_due_at, next_due_km,
               notes, is_active
        FROM fleet_maintenance_schedules
        WHERE vehicle_id = %s AND is_active = true
        ORDER BY next_due_at NULLS LAST, next_due_km NULLS LAST
    """, (vehicle_id,))

    schedules = []
    for r in cur.fetchall():
        schedules.append({
            'id': r[0], 'maintenance_type': r[1], 'interval_km': r[2],
            'interval_months': r[3],
            'last_done_at': str(r[4]) if r[4] else None,
            'last_done_km': r[5],
            'next_due_at': str(r[6]) if r[6] else None,
            'next_due_km': r[7],
            'notes': r[8], 'is_active': r[9],
        })

    cur.close()
    conn.close()
    return jsonify({'data': schedules})


@fleet_bp.route('/vehicles/<int:vehicle_id>/schedules', methods=['POST'])
@require_auth('fleet.create')
def create_schedule(vehicle_id):
    """Create maintenance schedule for a vehicle.

    Body: {maintenance_type, interval_km, interval_months, next_due_at, next_due_km, notes}
    """
    data = request.get_json() or {}
    if not data.get('maintenance_type'):
        return jsonify({'error': 'maintenance_type is required'}), 400

    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    # Verify vehicle exists
    cur.execute("SELECT id FROM fleet_vehicles WHERE id = %s", (vehicle_id,))
    if not cur.fetchone():
        cur.close(); conn.close()
        return jsonify({'error': 'Vehicle not found'}), 404

    try:
        cur.execute("""
            INSERT INTO fleet_maintenance_schedules
                (vehicle_id, maintenance_type, interval_km, interval_months,
                 next_due_at, next_due_km, notes)
            VALUES (%s,%s,%s,%s,%s,%s,%s)
            RETURNING id
        """, (
            vehicle_id, data['maintenance_type'],
            data.get('interval_km'), data.get('interval_months'),
            data.get('next_due_at'), data.get('next_due_km'),
            data.get('notes'),
        ))
        schedule_id = cur.fetchone()[0]
        conn.commit()
        cur.close(); conn.close()
        return jsonify({'id': schedule_id, 'message': 'Schedule created'}), 201
    except Exception as e:
        conn.rollback()
        cur.close(); conn.close()
        return jsonify({'error': str(e)}), 500


# ─── Maintenance Logs ─────────────────────────────

@fleet_bp.route('/vehicles/<int:vehicle_id>/log', methods=['POST'])
@require_auth('fleet.create')
def record_maintenance(vehicle_id):
    """Record maintenance done. Updates schedule next_due if schedule_id provided.

    Body: {schedule_id, maintenance_type, mileage_at, cost, parts_used, notes}
    """
    data = request.get_json() or {}
    if not data.get('maintenance_type'):
        return jsonify({'error': 'maintenance_type is required'}), 400

    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    # Verify vehicle exists
    cur.execute("SELECT id, current_mileage FROM fleet_vehicles WHERE id = %s", (vehicle_id,))
    veh = cur.fetchone()
    if not veh:
        cur.close(); conn.close()
        return jsonify({'error': 'Vehicle not found'}), 404

    mileage_at = data.get('mileage_at', veh[1] or 0)
    schedule_id = data.get('schedule_id')

    try:
        # Insert log
        cur.execute("""
            INSERT INTO fleet_maintenance_logs
                (vehicle_id, schedule_id, maintenance_type, mileage_at,
                 cost, parts_used, employee_id, notes)
            VALUES (%s,%s,%s,%s,%s,%s,%s,%s)
            RETURNING id
        """, (
            vehicle_id, schedule_id, data['maintenance_type'],
            mileage_at, data.get('cost', 0), data.get('parts_used'),
            getattr(g, 'employee_id', None), data.get('notes'),
        ))
        log_id = cur.fetchone()[0]

        # Update vehicle mileage if new mileage is higher
        if mileage_at > (veh[1] or 0):
            cur.execute("UPDATE fleet_vehicles SET current_mileage = %s WHERE id = %s",
                        (mileage_at, vehicle_id))

        # Update schedule next_due if schedule_id provided
        if schedule_id:
            cur.execute("""
                SELECT interval_km, interval_months
                FROM fleet_maintenance_schedules WHERE id = %s
            """, (schedule_id,))
            sched = cur.fetchone()
            if sched:
                interval_km, interval_months = sched
                now = datetime.utcnow()

                next_due_km = (mileage_at + interval_km) if interval_km else None
                next_due_at = None
                if interval_months:
                    next_due_at = now + timedelta(days=interval_months * 30)

                cur.execute("""
                    UPDATE fleet_maintenance_schedules
                    SET last_done_at = %s, last_done_km = %s,
                        next_due_at = %s, next_due_km = %s
                    WHERE id = %s
                """, (now, mileage_at, next_due_at, next_due_km, schedule_id))

        log_action(conn, 'FLEET_MAINTENANCE_LOG', 'fleet_vehicle', vehicle_id,
                   new_value={'maintenance_type': data['maintenance_type'],
                              'mileage_at': mileage_at, 'cost': data.get('cost', 0)})

        conn.commit()
        cur.close(); conn.close()
        return jsonify({'id': log_id, 'message': 'Maintenance recorded'}), 201

    except Exception as e:
        conn.rollback()
        cur.close(); conn.close()
        return jsonify({'error': str(e)}), 500


# ─── Alerts ─────────────────────────────

@fleet_bp.route('/alerts', methods=['GET'])
@require_auth('fleet.view')
def fleet_alerts():
    """Vehicles with overdue maintenance (next_due_at < NOW() or next_due_km < current_mileage)."""
    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    branch_filter = ""
    params = []
    if g.branch_id:
        branch_filter = "AND v.branch_id = %s"
        params.append(g.branch_id)

    cur.execute(f"""
        SELECT v.id, v.plate, v.make, v.model, v.year, v.current_mileage,
               s.id as schedule_id, s.maintenance_type,
               s.next_due_at, s.next_due_km
        FROM fleet_maintenance_schedules s
        JOIN fleet_vehicles v ON s.vehicle_id = v.id
        WHERE s.is_active = true AND v.is_active = true
          {branch_filter}
          AND (
              (s.next_due_at IS NOT NULL AND s.next_due_at < NOW())
              OR (s.next_due_km IS NOT NULL AND s.next_due_km <= v.current_mileage)
          )
        ORDER BY s.next_due_at NULLS LAST
    """, params)

    alerts = []
    for r in cur.fetchall():
        alerts.append({
            'vehicle_id': r[0], 'plate': r[1], 'make': r[2], 'model': r[3],
            'year': r[4], 'current_mileage': r[5],
            'schedule_id': r[6], 'maintenance_type': r[7],
            'next_due_at': str(r[8]) if r[8] else None,
            'next_due_km': r[9],
        })

    cur.close()
    conn.close()
    return jsonify({'data': alerts, 'total': len(alerts)})


# ─── Stats ─────────────────────────────

@fleet_bp.route('/stats', methods=['GET'])
@require_auth('fleet.view')
def fleet_stats():
    """Fleet summary: total vehicles, overdue count, upcoming this month, total cost this month."""
    conn = get_tenant_conn(g.tenant_id)
    cur = conn.cursor()

    branch_filter = ""
    params = []
    if g.branch_id:
        branch_filter = "AND v.branch_id = %s"
        params.append(g.branch_id)

    # Total active vehicles
    cur.execute(f"""
        SELECT count(*) FROM fleet_vehicles v
        WHERE v.is_active = true {branch_filter}
    """, params)
    total_vehicles = cur.fetchone()[0]

    # Overdue count
    cur.execute(f"""
        SELECT count(DISTINCT v.id)
        FROM fleet_maintenance_schedules s
        JOIN fleet_vehicles v ON s.vehicle_id = v.id
        WHERE s.is_active = true AND v.is_active = true
          {branch_filter}
          AND (
              (s.next_due_at IS NOT NULL AND s.next_due_at < NOW())
              OR (s.next_due_km IS NOT NULL AND s.next_due_km <= v.current_mileage)
          )
    """, params)
    overdue_count = cur.fetchone()[0]

    # Upcoming this month
    cur.execute(f"""
        SELECT count(*)
        FROM fleet_maintenance_schedules s
        JOIN fleet_vehicles v ON s.vehicle_id = v.id
        WHERE s.is_active = true AND v.is_active = true
          {branch_filter}
          AND s.next_due_at IS NOT NULL
          AND s.next_due_at >= NOW()
          AND s.next_due_at < date_trunc('month', NOW()) + interval '1 month'
    """, params)
    upcoming_this_month = cur.fetchone()[0]

    # Total cost this month
    cur.execute(f"""
        SELECT COALESCE(SUM(l.cost), 0)
        FROM fleet_maintenance_logs l
        JOIN fleet_vehicles v ON l.vehicle_id = v.id
        WHERE v.is_active = true
          {branch_filter}
          AND l.created_at >= date_trunc('month', NOW())
    """, params)
    total_cost_month = float(cur.fetchone()[0])

    cur.close()
    conn.close()

    return jsonify({
        'total_vehicles': total_vehicles,
        'overdue_count': overdue_count,
        'upcoming_this_month': upcoming_this_month,
        'total_cost_month': total_cost_month,
    })
