<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Models;

use App\Models\Concerns\HasDberpAuditTrail;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Validation\ValidationException;

class DberpSalesperson extends Model
{
    use HasDberpAuditTrail;

    protected $table = 'dberp_salespersons';

    /**
     * @var list<string>
     */
    protected $fillable = [
        'employee_id',
        'department_id',
        'position_id',
        'name',
        'department_text',
        'position_text',
        'phone',
        'is_enabled',
        'sort_order',
        'remark',
    ];

    protected function casts(): array
    {
        return [
            'employee_id' => 'integer',
            'department_id' => 'integer',
            'position_id' => 'integer',
            'is_enabled' => 'boolean',
            'sort_order' => 'integer',
        ];
    }

    public function getDberpAuditActionPrefix(): string
    {
        return 'dberp.salesperson';
    }

    /**
     * @return list<string>
     */
    public function getDberpAuditFields(): array
    {
        return $this->getFillable();
    }

    public function employee(): BelongsTo
    {
        return $this->belongsTo(DberpEmployee::class, 'employee_id');
    }

    public function department(): BelongsTo
    {
        return $this->belongsTo(DberpDepartment::class, 'department_id');
    }

    public function position(): BelongsTo
    {
        return $this->belongsTo(DberpPosition::class, 'position_id');
    }

    public function resolvedDisplayName(): string
    {
        $employee = $this->employee;

        return $employee?->name
            ?? (filled($this->name) ? (string) $this->name : (string) __('dberp.labels.master_not_set'));
    }

    public function resolvedDepartmentLabel(): string
    {
        $employee = $this->employee;
        if ($employee !== null) {
            $deptName = $employee->department?->name;
            if (filled($deptName)) {
                return (string) $deptName;
            }

            if (filled($employee->department_name)) {
                return (string) $employee->department_name;
            }
        }

        $dept = $this->department;
        if ($dept !== null && filled($dept->name)) {
            return (string) $dept->name;
        }

        return filled($this->department_text)
            ? (string) $this->department_text
            : (string) __('dberp.labels.master_not_set');
    }

    public function resolvedPositionLabel(): string
    {
        $employee = $this->employee;
        if ($employee !== null) {
            $posName = $employee->position?->name;
            if (filled($posName)) {
                return (string) $posName;
            }

            if (filled($employee->position_name)) {
                return (string) $employee->position_name;
            }
        }

        $pos = $this->position;
        if ($pos !== null && filled($pos->name)) {
            return (string) $pos->name;
        }

        return filled($this->position_text)
            ? (string) $this->position_text
            : (string) __('dberp.labels.master_not_set');
    }

    public function resolvedPhoneLabel(): string
    {
        $employee = $this->employee;
        if ($employee !== null) {
            $fromEmployee = $employee->mobile;
            if (filled($fromEmployee)) {
                return (string) $fromEmployee;
            }
        }

        return filled($this->phone) ? (string) $this->phone : (string) __('dberp.labels.master_not_set');
    }

    /**
     * 下拉展示：业务员展示名后附部门、岗位（与职员主档规则一致）；无部门岗位时仅展示名。
     */
    public function labelForSelectWithOrganization(): string
    {
        $name = $this->resolvedDisplayName();
        $dept = $this->resolvedDepartmentLabel();
        $pos = $this->resolvedPositionLabel();
        $notSet = (string) __('dberp.labels.master_not_set');

        $segments = [];
        if ($dept !== $notSet) {
            $segments[] = $dept;
        }
        if ($pos !== $notSet) {
            $segments[] = $pos;
        }

        if ($segments === []) {
            return $name;
        }

        return sprintf('%s（%s）', $name, implode(' / ', $segments));
    }

    /**
     * @param  array<string, mixed>  $data
     * @return array<string, mixed>
     */
    public static function syncSnapshotFieldsFromEmployee(array $data): array
    {
        if (empty($data['employee_id'])) {
            return $data;
        }

        $employee = DberpEmployee::query()->with(['department', 'position'])->find((int) $data['employee_id']);
        if ($employee === null) {
            return $data;
        }

        $data['name'] = $employee->name;

        $data['department_id'] = $employee->department_id;
        $data['position_id'] = $employee->position_id;

        $departmentLabel = $employee->department?->name ?? $employee->department_name;
        $data['department_text'] = filled($departmentLabel) ? (string) $departmentLabel : null;

        $positionLabel = $employee->position?->name ?? $employee->position_name;
        $data['position_text'] = filled($positionLabel) ? (string) $positionLabel : null;

        $phone = $employee->mobile;
        $data['phone'] = filled($phone) ? (string) $phone : null;

        return $data;
    }

    public static function assertUniqueActiveEmployeeLink(?int $employeeId, ?int $ignoreSalespersonId): void
    {
        if ($employeeId === null) {
            return;
        }

        $query = self::query()
            ->where('employee_id', $employeeId)
            ->where('is_enabled', true);

        if ($ignoreSalespersonId !== null) {
            $query->whereKeyNot($ignoreSalespersonId);
        }

        if ($query->exists()) {
            throw ValidationException::withMessages([
                'employee_id' => __('dberp.errors.salesperson_duplicate_active_employee'),
            ]);
        }
    }

    /**
     * 业务员档案表单：关联职员下拉（默认仅启用且「可作为业务员」的职员；编辑时可保留当前已选但已停用或非业务员的职员）。
     *
     * @return array<int, string>
     */
    public static function employeeSelectOptionsForForm(?int $preserveEmployeeId): array
    {
        $out = DberpEmployee::selectOptionsForFilament(
            fn (Builder $q) => $q->where('is_enabled', true)->where('is_salesperson', true),
            $preserveEmployeeId,
        );

        if ($preserveEmployeeId === null || array_key_exists($preserveEmployeeId, $out)) {
            return $out;
        }

        $extra = DberpEmployee::query()->with(['department', 'position'])->find($preserveEmployeeId);
        if ($extra === null) {
            return $out;
        }

        $suffixes = [];
        if (! $extra->is_enabled) {
            $suffixes[] = (string) __('dberp.labels.master_disabled_suffix');
        }
        if (! $extra->is_salesperson) {
            $suffixes[] = (string) __('dberp.labels.master_not_salesperson_suffix');
        }

        if ($suffixes === []) {
            return $out;
        }

        $out[$preserveEmployeeId] = sprintf(
            '%s（%s）',
            $extra->labelForSelectWithOrganization(),
            implode('、', $suffixes),
        );

        return $out;
    }

    /**
     * 新建或更换关联职员时，须为启用且标记为可作为业务员的职员；编辑时保留原有关联不变。
     */
    public static function assertEmployeeEligibleForSalespersonLink(
        ?int $employeeId,
        ?int $currentEmployeeIdOnRecord,
    ): void {
        if ($employeeId === null) {
            return;
        }

        if ($currentEmployeeIdOnRecord !== null && $employeeId === $currentEmployeeIdOnRecord) {
            return;
        }

        $employee = DberpEmployee::query()->find($employeeId);
        if ($employee === null) {
            throw ValidationException::withMessages([
                'employee_id' => __('dberp.errors.salesperson_invalid_linked_employee'),
            ]);
        }

        if (! $employee->is_enabled || ! $employee->is_salesperson) {
            throw ValidationException::withMessages([
                'employee_id' => __('dberp.errors.salesperson_employee_must_be_salesperson'),
            ]);
        }
    }

    /**
     * @return array{department: string, position: string}
     */
    public static function previewOrganizationLabelsForEmployeeId(?int $employeeId): array
    {
        $notSet = (string) __('dberp.labels.master_not_set');

        if ($employeeId === null) {
            return ['department' => $notSet, 'position' => $notSet];
        }

        $employee = DberpEmployee::query()->with(['department', 'position'])->find($employeeId);
        if ($employee === null) {
            return ['department' => $notSet, 'position' => $notSet];
        }

        $departmentLabel = $employee->department?->name ?? $employee->department_name;
        $positionLabel = $employee->position?->name ?? $employee->position_name;

        return [
            'department' => filled($departmentLabel) ? (string) $departmentLabel : $notSet,
            'position' => filled($positionLabel) ? (string) $positionLabel : $notSet,
        ];
    }

    /**
     * 客户主档表单：业务员归属下拉（可选启用中的业务员档案；编辑时可保留当前已选但已停用的业务员或员工）。
     *
     * 选项值为关联员工 id，与 `dberp_customers.salesperson_employee_id` 一致；无关联员工的业务员无法写入该字段，故不出现在列表中。
     *
     * @return array<int, string>
     */
    public static function optionsForCustomerMasterForm(?int $preserveEmployeeId): array
    {
        $out = [];

        foreach (static::query()
            ->where('is_enabled', true)
            ->whereNotNull('employee_id')
            ->with(['employee.department', 'employee.position', 'department', 'position'])
            ->orderBy('sort_order')
            ->orderBy('id')
            ->cursor() as $salesperson) {
            $employeeId = (int) $salesperson->employee_id;
            $out[$employeeId] = $salesperson->labelForSelectWithOrganization();
        }

        if ($preserveEmployeeId === null) {
            return $out;
        }

        if (array_key_exists($preserveEmployeeId, $out)) {
            return $out;
        }

        $salesperson = static::query()
            ->where('employee_id', $preserveEmployeeId)
            ->with(['employee.department', 'employee.position', 'department', 'position'])
            ->orderByDesc('is_enabled')
            ->orderByDesc('id')
            ->first();

        if ($salesperson !== null) {
            $label = $salesperson->labelForSelectWithOrganization();
            if (! $salesperson->is_enabled) {
                $label .= '（'.__('dberp.labels.master_disabled_suffix').'）';
            } elseif ($salesperson->employee !== null && ! $salesperson->employee->is_enabled) {
                $label .= '（'.__('dberp.labels.master_disabled_suffix').'）';
            }

            $out[$preserveEmployeeId] = $label;

            return $out;
        }

        $employee = DberpEmployee::query()->with(['department', 'position'])->find($preserveEmployeeId);
        if ($employee !== null) {
            $out[$preserveEmployeeId] = sprintf(
                '%s（%s）',
                $employee->labelForSelectWithOrganization(),
                __('dberp.labels.master_disabled_suffix'),
            );
        }

        return $out;
    }
}
