"""Logistics Engine: shipment tracking and courier management.

Supports multiple couriers: DHL, FedEx, Estafeta, 99 Minutos, Uber Direct.
Provides tracking URL generation, status updates, and history logging.
"""

from datetime import datetime


def create_shipment(conn, data):
    """Create a new shipment record.

    data: {
        tenant_id, branch_id, shipment_type, related_type, related_id,
        courier_id, tracking_number, origin_address, destination_address,
        recipient_name, recipient_phone, estimated_delivery,
        shipping_cost, weight_kg, dimensions_cm, notes, created_by
    }
    """
    cur = conn.cursor()

    # Generate tracking URL if template exists
    tracking_url = None
    if data.get('courier_id') and data.get('tracking_number'):
        cur.execute("SELECT tracking_url_template FROM couriers WHERE id = %s", (data['courier_id'],))
        row = cur.fetchone()
        if row and row[0]:
            tracking_url = row[0].replace('{tracking_number}', data['tracking_number'])

    cur.execute("""
        INSERT INTO shipments
            (tenant_id, branch_id, shipment_type, related_type, related_id,
             courier_id, tracking_number, tracking_url, status,
             origin_address, destination_address, recipient_name, recipient_phone,
             estimated_delivery, shipping_cost, weight_kg, dimensions_cm, notes, created_by)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, 'pending',
                %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        RETURNING id
    """, (
        data.get('tenant_id'), data.get('branch_id'), data.get('shipment_type', 'outbound'),
        data.get('related_type'), data.get('related_id'),
        data.get('courier_id'), data.get('tracking_number'), tracking_url,
        data.get('origin_address'), data.get('destination_address'),
        data.get('recipient_name'), data.get('recipient_phone'),
        data.get('estimated_delivery'), data.get('shipping_cost', 0),
        data.get('weight_kg'), data.get('dimensions_cm'),
        data.get('notes'), data.get('created_by'),
    ))
    shipment_id = cur.fetchone()[0]

    # Log initial tracking entry
    if tracking_url:
        cur.execute("""
            INSERT INTO shipment_tracking (shipment_id, status, description)
            VALUES (%s, 'pending', 'Envío registrado')
        """, (shipment_id,))

    conn.commit()
    cur.close()
    return {'shipment_id': shipment_id, 'tracking_url': tracking_url}


def get_shipment(conn, shipment_id):
    cur = conn.cursor()
    cur.execute("""
        SELECT s.id, s.shipment_type, s.related_type, s.related_id,
               s.courier_id, c.name as courier_name, s.tracking_number, s.tracking_url,
               s.status, s.origin_address, s.destination_address,
               s.recipient_name, s.recipient_phone, s.estimated_delivery,
               s.actual_delivery, s.shipping_cost, s.weight_kg, s.dimensions_cm,
               s.notes, s.created_at, s.updated_at
        FROM shipments s
        LEFT JOIN couriers c ON s.courier_id = c.id
        WHERE s.id = %s
    """, (shipment_id,))
    row = cur.fetchone()
    if not row:
        cur.close()
        return None

    shipment = {
        'id': row[0], 'shipment_type': row[1], 'related_type': row[2],
        'related_id': row[3], 'courier_id': row[4], 'courier_name': row[5],
        'tracking_number': row[6], 'tracking_url': row[7],
        'status': row[8], 'origin_address': row[9], 'destination_address': row[10],
        'recipient_name': row[11], 'recipient_phone': row[12],
        'estimated_delivery': str(row[13]) if row[13] else None,
        'actual_delivery': str(row[14]) if row[14] else None,
        'shipping_cost': float(row[15]) if row[15] else 0,
        'weight_kg': float(row[16]) if row[16] else None,
        'dimensions_cm': row[17], 'notes': row[18],
        'created_at': str(row[19]), 'updated_at': str(row[20]),
    }

    # Tracking history
    cur.execute("""
        SELECT id, status, location, description, tracked_at
        FROM shipment_tracking
        WHERE shipment_id = %s
        ORDER BY tracked_at DESC
    """, (shipment_id,))
    shipment['tracking_history'] = []
    for r in cur.fetchall():
        shipment['tracking_history'].append({
            'id': r[0], 'status': r[1], 'location': r[2],
            'description': r[3], 'tracked_at': str(r[4]),
        })

    cur.close()
    return shipment


def list_shipments(conn, tenant_id, status=None, courier_id=None, related_type=None,
                   related_id=None, page=1, per_page=50):
    cur = conn.cursor()
    where = ["tenant_id = %s"]
    params = [tenant_id]
    if status:
        where.append("status = %s")
        params.append(status)
    if courier_id:
        where.append("courier_id = %s")
        params.append(courier_id)
    if related_type:
        where.append("related_type = %s")
        params.append(related_type)
    if related_id:
        where.append("related_id = %s")
        params.append(related_id)

    where_str = " AND ".join(where)

    cur.execute(f"SELECT count(*) FROM shipments WHERE {where_str}", params)
    total = cur.fetchone()[0]

    extra_where = ""
    if len(where) > 1:
        extra_where = " AND " + " AND ".join(where[1:])

    cur.execute(f"""
        SELECT s.id, s.shipment_type, s.related_type, s.related_id,
               c.name as courier_name, s.tracking_number, s.status,
               s.recipient_name, s.estimated_delivery, s.created_at
        FROM shipments s
        LEFT JOIN couriers c ON s.courier_id = c.id
        WHERE s.tenant_id = %s {extra_where}
        ORDER BY s.created_at DESC
        LIMIT %s OFFSET %s
    """, params + [per_page, (page - 1) * per_page])

    shipments = []
    for r in cur.fetchall():
        shipments.append({
            'id': r[0], 'shipment_type': r[1], 'related_type': r[2],
            'related_id': r[3], 'courier_name': r[4], 'tracking_number': r[5],
            'status': r[6], 'recipient_name': r[7],
            'estimated_delivery': str(r[8]) if r[8] else None,
            'created_at': str(r[9]),
        })

    cur.close()
    return {
        'data': shipments,
        'pagination': {'page': page, 'per_page': per_page, 'total': total}
    }


def update_shipment_status(conn, shipment_id, new_status, location=None,
                           description=None, raw_response=None):
    """Update shipment status and log tracking history."""
    cur = conn.cursor()

    cur.execute("SELECT status FROM shipments WHERE id = %s", (shipment_id,))
    row = cur.fetchone()
    if not row:
        cur.close()
        raise ValueError("Shipment not found")

    old_status = row[0]

    # Update shipment
    extra_sets = []
    extra_vals = []
    if new_status == 'delivered':
        extra_sets.append("actual_delivery = NOW()")

    set_clause = ", ".join(["status = %s"] + extra_sets)
    cur.execute(f"""
        UPDATE shipments SET {set_clause} WHERE id = %s
    """, [new_status] + extra_vals + [shipment_id])

    # Log tracking history
    cur.execute("""
        INSERT INTO shipment_tracking (shipment_id, status, location, description, raw_response)
        VALUES (%s, %s, %s, %s, %s)
    """, (shipment_id, new_status, location, description, raw_response))

    conn.commit()
    cur.close()
    return {'old_status': old_status, 'new_status': new_status}


def get_couriers(conn, tenant_id):
    cur = conn.cursor()
    cur.execute("""
        SELECT id, name, code, tracking_url_template, api_endpoint, is_active
        FROM couriers
        WHERE tenant_id = %s
        ORDER BY name
    """, (tenant_id,))
    couriers = []
    for r in cur.fetchall():
        couriers.append({
            'id': r[0], 'name': r[1], 'code': r[2],
            'tracking_url_template': r[3], 'api_endpoint': r[4], 'is_active': r[5],
        })
    cur.close()
    return couriers


def add_courier(conn, tenant_id, name, code, tracking_url_template=None,
                api_endpoint=None, is_active=True):
    cur = conn.cursor()
    cur.execute("""
        INSERT INTO couriers (tenant_id, name, code, tracking_url_template, api_endpoint, is_active)
        VALUES (%s, %s, %s, %s, %s, %s)
        RETURNING id
    """, (tenant_id, name, code, tracking_url_template, api_endpoint, is_active))
    cid = cur.fetchone()[0]
    conn.commit()
    cur.close()
    return cid
