<?php

declare(strict_types=1);

namespace App\Business\MasterData;

use App\Models\DberpCustomerCategory;
use App\Models\DberpDepartment;
use App\Models\DberpEmployee;
use App\Models\DberpProduct;
use App\Models\DberpProductBrand;
use App\Models\DberpProductCategory;
use App\Models\DberpSupplierCategory;
use App\Models\DberpSystemProfile;
use App\Models\DberpUnit;
use App\Models\DberpWarehouse;
use App\Services\DberpAuditService;
use Filament\Notifications\Notification;
use Filament\Support\Exceptions\Halt;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Schema;

final class MasterDataDeleteGuard
{
    public function ensureCanDelete(Model $model): void
    {
        $reasons = match (true) {
            $model instanceof DberpProductCategory => $this->categoryReasons($model),
            $model instanceof DberpCustomerCategory => $this->customerCategoryReasons($model),
            $model instanceof DberpSupplierCategory => $this->supplierCategoryReasons($model),
            $model instanceof DberpUnit => $this->unitReasons($model),
            $model instanceof DberpEmployee => $this->employeeReasons($model),
            $model instanceof DberpWarehouse => $this->warehouseReasons($model),
            $model instanceof DberpProductBrand => $this->productBrandReasons($model),
            $model instanceof DberpDepartment => $this->departmentReasons($model),
            default => [],
        };

        if ($reasons === []) {
            return;
        }

        if (Auth::check()) {
            app(DberpAuditService::class)->log(
                'dberp.master_data.delete_blocked',
                $model,
                null,
                ['reasons' => $reasons],
            );
        }

        $body = implode('；', $reasons);

        Notification::make()
            ->danger()
            ->title((string) __('dberp.ui.master_data_delete_blocked_title'))
            ->body($body)
            ->persistent()
            ->send();

        throw (new Halt)->rollBackDatabaseTransaction();
    }

    /**
     * @return list<string>
     */
    private function categoryReasons(DberpProductCategory $category): array
    {
        $reasons = [];

        if ($category->children()->exists()) {
            $reasons[] = __('dberp.errors.category_has_children');
        }

        if ($category->products()->exists()) {
            $reasons[] = __('dberp.errors.category_has_products');
        }

        return $reasons;
    }

    /**
     * @return list<string>
     */
    private function customerCategoryReasons(DberpCustomerCategory $category): array
    {
        if ($category->customers()->exists()) {
            return [__('dberp.errors.customer_category_referenced_by_customers')];
        }

        return [];
    }

    /**
     * @return list<string>
     */
    private function supplierCategoryReasons(DberpSupplierCategory $category): array
    {
        if ($category->suppliers()->exists()) {
            return [__('dberp.errors.supplier_category_referenced_by_suppliers')];
        }

        return [];
    }

    /**
     * @return list<string>
     */
    private function unitReasons(DberpUnit $unit): array
    {
        $reasons = [];

        if ($unit->products()->exists()) {
            $reasons[] = __('dberp.errors.unit_in_use');
        }

        if (Schema::hasColumn((new DberpProduct)->getTable(), 'auxiliary_unit_id') && $unit->productsUsingAsAuxiliaryUnit()->exists()) {
            $reasons[] = __('dberp.errors.unit_in_use_as_auxiliary');
        }

        return $reasons;
    }

    /**
     * @return list<string>
     */
    private function employeeReasons(DberpEmployee $employee): array
    {
        $reasons = [];

        if ($employee->managedWarehouses()->exists()) {
            $reasons[] = __('dberp.errors.employee_manages_warehouse');
        }

        if ($employee->salesCustomers()->exists()) {
            $reasons[] = __('dberp.errors.employee_owns_customer');
        }

        return $reasons;
    }

    /**
     * @return list<string>
     */
    private function warehouseReasons(DberpWarehouse $warehouse): array
    {
        $reasons = [];

        if (DberpSystemProfile::query()->where('default_warehouse_id', $warehouse->getKey())->exists()) {
            $reasons[] = __('dberp.errors.warehouse_is_default');
        }

        return $reasons;
    }

    /**
     * 商品品牌删除约束：待商品档案增加 brand_id 外键后，将在此按引用关系拦截删除。
     *
     * @return list<string>
     */
    private function productBrandReasons(DberpProductBrand $brand): array
    {
        $reasons = [];

        if (! Schema::hasColumn((new DberpProduct)->getTable(), 'brand_id')) {
            return $reasons;
        }

        if (DberpProduct::query()->where('brand_id', $brand->getKey())->exists()) {
            $reasons[] = __('dberp.errors.product_brand_referenced_by_products');
        }

        return $reasons;
    }

    /**
     * @return list<string>
     */
    private function departmentReasons(DberpDepartment $department): array
    {
        $reasons = [];

        if ($department->children()->exists()) {
            $reasons[] = __('dberp.errors.department_has_children');
        }

        if ($department->positions()->exists()) {
            $reasons[] = __('dberp.errors.department_has_positions');
        }

        return $reasons;
    }
}
