<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;

/**
 * Makes today's accidental "empty user_warehouse_access list = sees every
 * branch" fallback (see CurrentContext::accessibleBranchIds()) an explicit,
 * intentional grant before that fallback is removed from application code —
 * otherwise every user currently relying on it would be locked out of every
 * branch the moment the new code ships. Must run in the same release as that
 * code change, after this migration (see docs in the plan / PR description).
 */
return new class extends Migration
{
    public function up(): void
    {
        // Full admins already see every branch unconditionally (BranchScope's
        // full-admin bypass, independent of user_warehouse_access) — recognize
        // that explicitly via the new flag rather than leaving it implicit.
        $fullAdminUserIds = DB::table('users as u')
            ->join('user_roles as ur', 'ur.user_id', '=', 'u.id')
            ->join('roles as r', 'r.id', '=', 'ur.role_id')
            ->where('r.is_full_admin', true)
            ->where('r.is_active', true)
            ->whereNull('r.deleted_at')
            ->distinct()
            ->pluck('u.id');

        if ($fullAdminUserIds->isNotEmpty()) {
            DB::table('users')->whereIn('id', $fullAdminUserIds)->update(['is_all_branches' => true]);
        }

        // Everyone else with zero explicit branch rows today is implicitly
        // unrestricted under the old fallback — make that explicit by granting
        // every active branch in their own tenant, so removing the fallback
        // doesn't silently lock them out.
        DB::table('users as u')
            ->leftJoin('user_warehouse_access as uwa', 'uwa.user_id', '=', 'u.id')
            ->whereNull('uwa.user_id')
            ->whereNotIn('u.id', $fullAdminUserIds)
            ->whereNotNull('u.tenant_id')
            ->select('u.id', 'u.tenant_id')
            ->distinct()
            ->orderBy('u.id')
            ->get()
            ->groupBy('tenant_id')
            ->each(function ($users, $tenantId) {
                $branchIds = DB::table('warehouses')
                    ->where('tenant_id', $tenantId)
                    ->where('is_active', true)
                    ->whereNull('deleted_at')
                    ->pluck('id');

                if ($branchIds->isEmpty()) {
                    return;
                }

                $rows = [];
                foreach ($users as $user) {
                    foreach ($branchIds as $branchId) {
                        $rows[] = ['user_id' => $user->id, 'warehouse_id' => $branchId];
                    }
                }

                foreach (array_chunk($rows, 500) as $chunk) {
                    DB::table('user_warehouse_access')->insertOrIgnore($chunk);
                }
            });
    }

    public function down(): void
    {
        // Intentionally a no-op: this migration only makes a pre-existing,
        // implicit access level explicit. There's no safe inverse — reverting
        // the schema columns those writes live in (the two preceding
        // migrations) is the real rollback path.
    }
};
