"""B2B delivery fleets — a business account (the same login it already orders
with) can register a company that operates its own trucks and drivers,
instead of relying on admin-registered pickers. Self-service, but a company
can't receive orders until an admin approves it (mirrors the existing
is_approved gate on self-signup B2C pickers)."""

from accounts.supabase_client import get_client


def get_company_for_user(owner_user_id):
    resp = get_client().table('pickker_fleet_companies').select('*').eq('owner_user_id', owner_user_id).execute()
    return resp.data[0] if resp.data else None


def get_company(company_id):
    if not company_id:
        return None
    resp = get_client().table('pickker_fleet_companies').select('*').eq('id', company_id).execute()
    return resp.data[0] if resp.data else None


def create_company(owner_user_id, company_name, registration_number='', region_id=None):
    company_name = (company_name or '').strip()
    if not company_name:
        return None
    if get_company_for_user(owner_user_id):
        return None
    resp = get_client().table('pickker_fleet_companies').insert({
        'owner_user_id': owner_user_id,
        'company_name': company_name,
        'business_registration_number': (registration_number or '').strip() or None,
        'region_id': region_id,
        'is_approved': False,
    }).execute()
    return resp.data[0] if resp.data else None


def update_company_region(company_id, region_id):
    """Informational only — a company's own declared home region doesn't
    restrict who it can serve (B2B stays interregional by design); it's
    just shown to admin and on the company's own dashboard."""
    get_client().table('pickker_fleet_companies').update({'region_id': region_id}).eq('id', company_id).execute()


def get_pending_companies():
    resp = get_client().table('pickker_fleet_companies').select('*').eq('is_approved', False).order('created_at').execute()
    return resp.data


def get_all_companies():
    resp = get_client().table('pickker_fleet_companies').select('*').order('created_at', desc=True).execute()
    return resp.data


def approve_company(company_id):
    get_client().table('pickker_fleet_companies').update({'is_approved': True}).eq('id', company_id).execute()


# --- Trucks -----------------------------------------------------------

def get_company_trucks(company_id):
    resp = get_client().table('pickker_fleet_trucks').select('*, truck_type:truck_type_id(*)').eq('company_id', company_id).order('created_at').execute()
    return resp.data


def get_truck(truck_id):
    if not truck_id:
        return None
    resp = get_client().table('pickker_fleet_trucks').select('*').eq('id', truck_id).execute()
    return resp.data[0] if resp.data else None


def add_truck(company_id, truck_type_id, nickname='', license_plate=''):
    resp = get_client().table('pickker_fleet_trucks').insert({
        'company_id': company_id,
        'truck_type_id': int(truck_type_id),
        'nickname': (nickname or '').strip(),
        'license_plate': (license_plate or '').strip(),
        'is_active': True,
    }).execute()
    return resp.data[0] if resp.data else None


def update_truck(truck_id, truck_type_id, nickname='', license_plate=''):
    get_client().table('pickker_fleet_trucks').update({
        'truck_type_id': int(truck_type_id),
        'nickname': (nickname or '').strip(),
        'license_plate': (license_plate or '').strip(),
    }).eq('id', truck_id).execute()


# --- Admin-side truck management (register/edit a truck on behalf of any
# company, with a real location and warehouse assignment) — separate from
# the plain company self-service add_truck/update_truck above, which never
# touch location or warehouse ties. -----------------------------------

def get_all_trucks_with_company():
    """Every truck across every company, for the admin truck-management
    page — no company-scoping, unlike get_company_trucks."""
    resp = (
        get_client().table('pickker_fleet_trucks')
        .select('*, truck_type:truck_type_id(*), company:company_id(*)')
        .order('created_at', desc=True)
        .execute()
    )
    return resp.data


def admin_create_truck(company_id, truck_type_id, nickname='', license_plate='', lat=None, lng=None):
    resp = get_client().table('pickker_fleet_trucks').insert({
        'company_id': company_id,
        'truck_type_id': int(truck_type_id),
        'nickname': (nickname or '').strip(),
        'license_plate': (license_plate or '').strip(),
        'is_active': True,
        'location_lat': lat,
        'location_lng': lng,
    }).execute()
    return resp.data[0] if resp.data else None


def admin_update_truck(truck_id, company_id, truck_type_id, nickname='', license_plate='', lat=None, lng=None):
    get_client().table('pickker_fleet_trucks').update({
        'company_id': company_id,
        'truck_type_id': int(truck_type_id),
        'nickname': (nickname or '').strip(),
        'license_plate': (license_plate or '').strip(),
        'location_lat': lat,
        'location_lng': lng,
    }).eq('id', truck_id).execute()


def admin_delete_truck(truck_id):
    get_client().table('pickker_truck_warehouses').delete().eq('truck_id', truck_id).execute()
    get_client().table('pickker_fleet_trucks').delete().eq('id', truck_id).execute()


def get_vendor_tie_options():
    """Every warehouse/industry/market a truck or B2B picker can be tied to
    serve — the combined 'vendor_key'/'vendor_type' shape all three tie
    forms (self-service picker_profile_edit, admin_edit_user, admin
    Fleet Trucks) render as one multi-select, and set_picker_warehouses/
    set_truck_warehouses both parse back. A single shared builder so the
    three forms can't silently drift out of sync with each other."""
    from .markets import get_active_markets
    from .vendors import get_all_vendors

    return (
        [{**v, 'vendor_type': 'warehouse', 'vendor_key': f"warehouse:{v['id']}"} for v in get_all_vendors('warehouse')]
        + [{**v, 'vendor_type': 'industry', 'vendor_key': f"industry:{v['id']}"} for v in get_all_vendors('industry')]
        + [{**m, 'vendor_type': 'market', 'vendor_key': f"market:{m['id']}"} for m in get_active_markets()]
    )


def get_truck_warehouses(truck_id):
    """[{vendor_type, vendor_id, name, ...}] — every warehouse/industry/
    market this truck is assigned to service, resolved to full vendor rows
    (get_vendor dispatches 'market' to market/markets.py, same as every
    other vendor-type-agnostic caller in this module)."""
    from .vendors import get_vendor

    resp = get_client().table('pickker_truck_warehouses').select('*').eq('truck_id', truck_id).execute()
    result = []
    for row in resp.data:
        vendor = get_vendor(row['warehouse_type'], row['warehouse_id'])
        if vendor:
            result.append({**vendor, 'vendor_type': row['warehouse_type'], 'vendor_id': row['warehouse_id']})
    return result


def set_truck_warehouses(truck_id, warehouse_keys):
    """Replaces every warehouse tie for this truck with the given list of
    'type:id' strings — a plain full-replace, matching how a multi-select
    form field naturally posts its selection."""
    client = get_client()
    client.table('pickker_truck_warehouses').delete().eq('truck_id', truck_id).execute()
    rows = []
    for key in warehouse_keys:
        if ':' not in key:
            continue
        vendor_type, _, vendor_id = key.partition(':')
        if vendor_type in ('warehouse', 'industry', 'market') and vendor_id.isdigit():
            rows.append({'truck_id': truck_id, 'warehouse_type': vendor_type, 'warehouse_id': int(vendor_id)})
    if rows:
        client.table('pickker_truck_warehouses').insert(rows).execute()


def get_truck_ids_for_warehouse(vendor_type, vendor_id):
    """Reverse of get_truck_warehouses — every truck_id explicitly assigned
    to service this exact warehouse/industry/market, used at checkout to
    prefer a truck that's a real, checkable match rather than just 'same
    company'."""
    resp = (
        get_client().table('pickker_truck_warehouses')
        .select('truck_id').eq('warehouse_type', vendor_type).eq('warehouse_id', vendor_id).execute()
    )
    return {row['truck_id'] for row in resp.data}


def get_picker_ids_for_warehouse(vendor_type, vendor_id):
    """Reverse of get_picker_warehouses — every picker user_id explicitly
    assigned to service this exact warehouse/industry."""
    resp = (
        get_client().table('pickker_picker_warehouses')
        .select('picker_user_id').eq('warehouse_type', vendor_type).eq('warehouse_id', vendor_id).execute()
    )
    return {row['picker_user_id'] for row in resp.data}


def get_picker_warehouses(picker_user_id):
    from .vendors import get_vendor

    resp = get_client().table('pickker_picker_warehouses').select('*').eq('picker_user_id', picker_user_id).execute()
    result = []
    for row in resp.data:
        vendor = get_vendor(row['warehouse_type'], row['warehouse_id'])
        if vendor:
            result.append({**vendor, 'vendor_type': row['warehouse_type'], 'vendor_id': row['warehouse_id']})
    return result


def set_picker_warehouses(picker_user_id, warehouse_keys):
    client = get_client()
    client.table('pickker_picker_warehouses').delete().eq('picker_user_id', picker_user_id).execute()
    rows = []
    for key in warehouse_keys:
        if ':' not in key:
            continue
        vendor_type, _, vendor_id = key.partition(':')
        if vendor_type in ('warehouse', 'industry', 'market') and vendor_id.isdigit():
            rows.append({'picker_user_id': picker_user_id, 'warehouse_type': vendor_type, 'warehouse_id': int(vendor_id)})
    if rows:
        client.table('pickker_picker_warehouses').insert(rows).execute()


def _set_truck_active(truck_id, is_active):
    get_client().table('pickker_fleet_trucks').update({'is_active': is_active}).eq('id', truck_id).execute()


def deactivate_truck(truck_id):
    _set_truck_active(truck_id, False)


def reactivate_truck(truck_id):
    _set_truck_active(truck_id, True)


def resolve_picker_truck_type(profile):
    """A fleet driver's truck_type_id is resolved from their assigned truck
    when set, falling back to the legacy direct truck_type_id column for
    non-fleet (admin-registered) B2B pickers — keeps every existing
    consumer of a picker's truck_type_id working unchanged either way."""
    if profile.get('truck_id'):
        truck = get_truck(profile['truck_id'])
        if truck:
            return truck['truck_type_id']
    return profile.get('truck_type_id')


# --- Drivers ------------------------------------------------------------

def get_company_drivers(company_id):
    resp = (
        get_client()
        .table('pickker_picker_profiles')
        .select('*, user:user_id(id, first_name, last_name, email, phone_number, is_active)')
        .eq('company_id', company_id)
        .execute()
    )
    return resp.data


def get_company_driver_ids(company_id):
    return [d['user_id'] for d in get_company_drivers(company_id)]


def invite_company_driver(company_id, email, first_name, last_name, phone_number, truck_id):
    from django.contrib.auth.hashers import make_password
    from django.urls import reverse
    from django.utils.crypto import get_random_string

    from accounts.models import Role
    from accounts.password_reset import create_reset_token_for_user
    from market.emailer import send_email

    email = (email or '').strip().lower()
    first_name = (first_name or '').strip()
    if not email or not first_name:
        return None, 'Name and email are required.'

    client = get_client()
    existing = client.table('pickker_users').select('id').eq('email', email).execute()
    if existing.data:
        return None, f'{email} is already registered.'

    truck = get_truck(truck_id)
    if not truck:
        return None, 'Choose a truck for this driver.'

    user_resp = client.table('pickker_users').insert({
        'email': email,
        'password_hash': make_password(get_random_string(32)),
        'role': Role.PICKER,
        'first_name': first_name,
        'last_name': (last_name or '').strip(),
        'phone_number': (phone_number or '').strip(),
        'preferred_language': 'en',
        'sms_language': 'sw',
        'is_verified': True,
        'is_active': True,
    }).execute()
    user = user_resp.data[0]

    client.table('pickker_picker_profiles').insert({
        'user_id': user['id'],
        'picker_segment': 'b2b',
        'company_id': company_id,
        'truck_id': truck['id'],
        'truck_type_id': truck['truck_type_id'],
        'is_approved': True,
    }).execute()

    token = create_reset_token_for_user(user['id'])
    return user, token


def get_company_for_picker(picker_id):
    """The fleet company a picker drives for, or None for a non-fleet
    (admin-registered) B2B picker / a B2C picker — used to label checkout
    options with which real company will deliver."""
    resp = get_client().table('pickker_picker_profiles').select('company_id').eq('user_id', picker_id).execute()
    if not resp.data or not resp.data[0].get('company_id'):
        return None
    return get_company(resp.data[0]['company_id'])


def reassign_driver_truck(driver_user_id, new_truck_id):
    truck = get_truck(new_truck_id)
    if not truck:
        return False
    get_client().table('pickker_picker_profiles').update({
        'truck_id': truck['id'],
        'truck_type_id': truck['truck_type_id'],
    }).eq('user_id', driver_user_id).execute()
    return True


# --- Per-company delivery calendar (optional override of the sitewide
# schedule — see market/site_settings.py::get_delivery_weekdays) ----------

_DEFAULT_COMPANY_DELIVERY_WEEKDAYS_FALLBACK = None  # None -> use the sitewide default


def get_company_delivery_weekdays(company_id):
    """Sorted list of weekday ints (Monday=0) this company delivers on —
    falls back to the sitewide default (site_settings.get_delivery_weekdays)
    when the company hasn't set its own, exactly like every other optional
    per-company override this session (region_id, etc.)."""
    from .site_settings import get_delivery_weekdays

    company = get_company(company_id)
    raw = (company or {}).get('delivery_weekdays')
    if not raw:
        return get_delivery_weekdays()
    try:
        return sorted({int(x) for x in raw.split(',') if x.strip() != ''}) or get_delivery_weekdays()
    except ValueError:
        return get_delivery_weekdays()


def update_company_delivery_weekdays(company_id, weekdays):
    """weekdays: an iterable of ints 0-6 (Monday=0), or an empty/falsy
    iterable to CLEAR the override and revert to the sitewide default —
    unlike the sitewide setting, an empty company calendar is valid (it
    just means "use the platform default"), so this never refuses to save."""
    cleaned = sorted({int(d) for d in weekdays if 0 <= int(d) <= 6}) if weekdays else []
    get_client().table('pickker_fleet_companies').update({
        'delivery_weekdays': ','.join(str(d) for d in cleaned) if cleaned else None,
    }).eq('id', company_id).execute()
    return True


# --- Order -> driver assignment (the order lands with the company first;
# the company decides internally which of its own drivers actually takes
# it — see market/views.py::checkout_provider for how orders get here with
# picker_id=None and company_id set) --------------------------------------

def get_assignment_sla_badge(order):
    """(hours_since_confirmed, css_class) for the informational "confirmed
    Xh ago, due for assignment within 24-48h" badge on the admin/company
    unassigned-orders queues — None entirely when confirmed_at isn't set
    yet (payment not even confirmed), so the clock can never look like
    it's running before that. Purely visual — never blocks assignment past
    48h, matching this codebase's own established fail-open convention for
    every other soft/uncertain signal (see market/picker_availability.py,
    market/regions.py, market/shop_payments.py, market/here_api.py)."""
    confirmed_at = order.get('confirmed_at')
    if not confirmed_at:
        return None
    from datetime import datetime, timezone
    confirmed_dt = datetime.fromisoformat(confirmed_at.replace('Z', '+00:00'))
    hours = (datetime.now(timezone.utc) - confirmed_dt).total_seconds() / 3600
    return round(hours), ('warn' if hours >= 24 else 'ok')


def get_unassigned_orders_for_company(company_id):
    """Orders that chose this company at checkout but have no driver
    assigned yet — the company's own 'Pending Assignment' queue."""
    resp = (
        get_client().table('pickker_orders').select('*')
        .eq('company_id', company_id).is_('picker_id', 'null').neq('status', 'cancelled')
        .order('created_at')
        .execute()
    )
    return resp.data


def get_all_unassigned_orders():
    """Same as get_unassigned_orders_for_company, but platform-wide — used
    by admin's own visibility/edit page over the assignment mechanism."""
    resp = (
        get_client().table('pickker_orders').select('*')
        .not_.is_('company_id', 'null').is_('picker_id', 'null').neq('status', 'cancelled')
        .order('created_at')
        .execute()
    )
    return resp.data


def assign_driver_to_order(order_id, driver_user_id, company_id=None):
    """The first-ever UPDATE of pickker_orders.picker_id post-creation.
    company_id, when given, scopes this to a company confirming the order
    is genuinely theirs to assign (self-service path); omitted for admin's
    own cross-company override. Returns (True, None) on success, or
    (False, reason) — reason is a short machine key the caller's view maps
    to a translated message, never shown raw to the user."""
    from datetime import datetime, timezone

    from .truck_types import get_truck_type

    client = get_client()
    order_resp = client.table('pickker_orders').select('*').eq('id', order_id).execute()
    order = order_resp.data[0] if order_resp.data else None
    if not order or not order.get('company_id'):
        return False, 'not_found'
    if company_id is not None and order['company_id'] != company_id:
        return False, 'not_found'
    if order.get('picker_id'):
        return False, 'already_assigned'

    profile_resp = client.table('pickker_picker_profiles').select('*').eq('user_id', driver_user_id).execute()
    profile = profile_resp.data[0] if profile_resp.data else None
    if not profile or profile.get('company_id') != order['company_id']:
        return False, 'driver_not_in_company'

    # The order's own truck_type_id was already filtered to weight-capable
    # types at checkout time (see market/views.py::_gather_b2b_candidates) —
    # reuse it as the weight-class proxy rather than re-deriving cargo
    # weight from order_items. A driver whose own truck can't match or
    # exceed that quoted class isn't a valid assignment, price stays
    # locked at the quote either way (this session's standing rule: never
    # recompute price after the fact).
    order_truck_type = get_truck_type(order.get('truck_type_id')) if order.get('truck_type_id') else None
    driver_truck_type_id = resolve_picker_truck_type(profile)
    driver_truck_type = get_truck_type(driver_truck_type_id) if driver_truck_type_id else None
    if order_truck_type and driver_truck_type and float(driver_truck_type['max_weight_kg']) < float(order_truck_type.get('max_weight_kg') or 0):
        return False, 'truck_too_small'
    if profile.get('location_lat') is None or profile.get('location_lng') is None:
        return False, 'driver_no_location'

    client.table('pickker_orders').update({
        'picker_id': driver_user_id,
        'picker_location_lat': profile['location_lat'],
        'picker_location_lng': profile['location_lng'],
        'assigned_at': datetime.now(timezone.utc).isoformat(),
    }).eq('id', order_id).execute()
    return True, None
