<?php

use App\Http\Controllers\Auth\DeviceTokenController;
use App\Http\Controllers\Auth\PinLoginController;
use App\Http\Controllers\BarcodeController;
use App\Http\Controllers\BarcodeLabelPrintController;
use App\Http\Controllers\BranchContextController;
use App\Http\Controllers\Central\ImpersonationController as CentralImpersonationController;
use App\Http\Controllers\ImpersonationController;
use App\Http\Controllers\InvoicePrintController;
use App\Http\Controllers\TestInstanceSyncController;
use App\Http\Middleware\CheckActiveUser;
use App\Http\Middleware\EnsureCentralAdmin;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Route;

// Site home. In subdomain mode the bare tenant domain redirects to the app
// panel. In path mode the bare domain carries no tenant at all, so it points
// at the master-control panel (see docs/path-based-tenancy-plan.md Phase 2).
Route::get('/', fn (): RedirectResponse => redirect(config('tenancy.routing') === 'path'
    ? '/'.config('tenancy.central_prefix')
    : '/app'))->name('home');

// TEMPORARY: the storage:link symlink isn't being followed by Apache on this
// host, so instead this copies the already-uploaded files from
// storage/app/public into a REAL public/storage directory. Visit once,
// confirm the message, then:
//   1. Add FILESYSTEM_PUBLIC_DISK_IS_PUBLIC_PATH=true to the server .env
//      (so future uploads write straight into public/storage too).
//   2. DELETE this route block and the File import.

// migrate
Route::get('/migrate', function () {
    $exitCode = Artisan::call('migrate', ['--force' => true]);

    return response()->json(['message' => 'Migration completed successfully.', 'exit_code' => $exitCode]);
})->name('migrate');

// seed
Route::get('/seed', function () {
    $exitCode = Artisan::call('db:seed', ['--force' => true]);

    return response()->json(['message' => 'Seeding completed successfully.', 'exit_code' => $exitCode]);
})->name('seed');

// Landlord impersonation launch. Named with the `filament.central.`
// prefix so IdentifyTenant's central-host route-name lock (subdomain mode
// only, which only allows Filament-panel-registered central routes through)
// admits this hand-rolled route too — see docs/migration-plan.md §1. In path
// mode the prefix is harmless (no route-name lock applies) and the route
// sits at the root next to the /admin panel, never inside a workspace.
Route::post('tenants/{tenant}/impersonate', [CentralImpersonationController::class, 'start'])
    ->middleware(['auth:central', EnsureCentralAdmin::class])
    ->name('filament.central.tenants.impersonate');

// Tenant-scoped routes. In path tenancy every route below carries the
// {workspace} first segment — the SAME parameter IdentifyTenant reads and
// URL::defaults() back-fills (docs/path-based-tenancy-plan.md Levers 1+2).
// Deliberately named "workspace", not "tenant", so it can never collide with
// the model-bound {tenant} of the route above, and so URL defaults can never
// clobber it.
Route::prefix(config('tenancy.routing') === 'path' ? '{workspace}' : '')->group(function () {
    // Landlord impersonation hand-off (token minted on the central panel).
    // Public: the target user is not yet authenticated on this tenant when the
    // link is hit. Under the workspace prefix so the tenant is resolvable from
    // the URL and the token's tenant_id is checked against it.
    // Ported verbatim from App\Http\Controllers\ImpersonationController.
    Route::get('impersonate/{token}', [ImpersonationController::class, 'consume'])
        ->where('token', '[A-Za-z0-9]+')
        ->name('impersonate.consume');

    // Quick PIN device login: deliberately outside both the guest and auth
    // middleware groups (see PinLoginController docblock) — reachable either way.
    Route::post('pin-login', [PinLoginController::class, 'store'])
        ->middleware('throttle:pin-login')
        ->name('pin-login');

    Route::middleware(['auth:web', CheckActiveUser::class])->group(function () {
        Route::post('impersonate/stop', [ImpersonationController::class, 'stop'])->name('impersonate.stop');

        // Invoice print. A bare document in its own tab rather than a Filament page,
        // because the print needs its own @page size and no chrome. Both stocks come
        // off the same blades the Master Control preview uses, so preview == print.
        // Permission (isms_invoices.view + the reps-see-their-own rule) is enforced
        // in the controller through InvoiceResource::canView().
        Route::get('invoices/{invoice}/print/{paper?}', InvoicePrintController::class)
            ->whereIn('paper', InvoicePrintController::PAPERS)
            ->name('invoices.print');

        // Product barcode images. Hot-linked by the Products table thumbnails and
        // the "View Barcode" modal, and ?download=1 serves the PNG as an attachment.
        // The product (tenant-scoped via model binding) decides the value: its own
        // barcode, or the auto-generated SKU when no barcode was ever set.
        Route::get('products/{product}/barcode.{format}', [BarcodeController::class, 'show'])
            ->whereIn('format', BarcodeController::FORMATS)
            ->name('barcode.show');

        // The same image for a shop-printed label, off its own code — the one that
        // carries the lot, the serial and the quantity through a scan.
        Route::get('barcode-labels/{barcodeLabel}/barcode.{format}', [BarcodeController::class, 'label'])
            ->whereIn('format', BarcodeController::FORMATS)
            ->name('barcode-labels.image');

        // A run of labels as a bare document with its own @page size, opened in its
        // own tab. `inventory_barcode_labels.print` is enforced in the controller.
        Route::get('barcode-labels/print', BarcodeLabelPrintController::class)
            ->name('barcode-labels.print');

        // Mints the Quick PIN "trusted device" token after any full credential login.
        Route::post('device-token', [DeviceTokenController::class, 'store'])->name('device-token.store');

        // Branch context (top-bar selector). Ported verbatim from the source's
        // BranchContextController; ResolveBranchContext reads the session value.
        Route::post('branch/select', [BranchContextController::class, 'select'])->name('branch.select');

        // Tenant-side "Sync from Live" (topbar button on test instances only).
        // The controller refuses anything that isn't a test environment, so this
        // route can never refresh — let alone wipe — a live tenant's data.
        Route::post('sync-from-live', [TestInstanceSyncController::class, 'sync'])->name('test-instance.sync-from-live');

        // Tenant-side "Sync Products from Live" — the catalog-only variant of the
        // above. Same test-only guard, merges only categories/subcategories/products.
        Route::post('sync-products-from-live', [TestInstanceSyncController::class, 'syncProducts'])->name('test-instance.sync-products-from-live');
    });
});
