<?php

namespace App\Services;

use App\Models\Documents\Document;
use App\Models\Tenants\Approval;
use App\Models\Tenants\ApprovalForm;
use App\Models\Tenants\ApprovalLine;
use App\Models\Tenants\ApprovalStep;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class ApprovalService extends Service
{
    public function __construct(
        protected TodayIssueObserverService $todayIssueService
    ) {}

    // =========================================================================
    // 결재 양식 관리
    // =========================================================================

    /**
     * 결재 양식 목록
     */
    public function formIndex(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        $query = ApprovalForm::query()
            ->where('tenant_id', $tenantId)
            ->with('creator:id,name');

        // 카테고리 필터
        if (! empty($params['category'])) {
            $query->where('category', $params['category']);
        }

        // 활성 상태 필터
        if (isset($params['is_active'])) {
            $query->where('is_active', $params['is_active']);
        }

        // 검색
        if (! empty($params['search'])) {
            $query->where(function ($q) use ($params) {
                $q->where('name', 'like', "%{$params['search']}%")
                    ->orWhere('code', 'like', "%{$params['search']}%");
            });
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'created_at';
        $sortDir = $params['sort_dir'] ?? 'desc';
        $query->orderBy($sortBy, $sortDir);

        $perPage = $params['per_page'] ?? 20;

        return $query->paginate($perPage);
    }

    /**
     * 활성 결재 양식 목록 (셀렉트박스용)
     */
    public function formActive(): Collection
    {
        $tenantId = $this->tenantId();

        return ApprovalForm::query()
            ->where('tenant_id', $tenantId)
            ->active()
            ->orderBy('name')
            ->get(['id', 'name', 'code', 'category']);
    }

    /**
     * 결재 양식 상세
     */
    public function formShow(int $id): ApprovalForm
    {
        $tenantId = $this->tenantId();

        return ApprovalForm::query()
            ->where('tenant_id', $tenantId)
            ->with('creator:id,name')
            ->findOrFail($id);
    }

    /**
     * 결재 양식 생성
     */
    public function formStore(array $data): ApprovalForm
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 코드 중복 확인
        $exists = ApprovalForm::query()
            ->where('tenant_id', $tenantId)
            ->where('code', $data['code'])
            ->exists();

        if ($exists) {
            throw new BadRequestHttpException(__('error.approval.form_code_exists'));
        }

        return ApprovalForm::create([
            'tenant_id' => $tenantId,
            'name' => $data['name'],
            'code' => $data['code'],
            'category' => $data['category'] ?? null,
            'template' => $data['template'],
            'is_active' => $data['is_active'] ?? true,
            'created_by' => $userId,
            'updated_by' => $userId,
        ]);
    }

    /**
     * 결재 양식 수정
     */
    public function formUpdate(int $id, array $data): ApprovalForm
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $form = ApprovalForm::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($id);

        // 코드 중복 확인 (자기 자신 제외)
        if (isset($data['code']) && $data['code'] !== $form->code) {
            $exists = ApprovalForm::query()
                ->where('tenant_id', $tenantId)
                ->where('code', $data['code'])
                ->where('id', '!=', $id)
                ->exists();

            if ($exists) {
                throw new BadRequestHttpException(__('error.approval.form_code_exists'));
            }
        }

        $form->fill([
            'name' => $data['name'] ?? $form->name,
            'code' => $data['code'] ?? $form->code,
            'category' => $data['category'] ?? $form->category,
            'template' => $data['template'] ?? $form->template,
            'is_active' => $data['is_active'] ?? $form->is_active,
            'updated_by' => $userId,
        ]);

        $form->save();

        return $form->fresh('creator:id,name');
    }

    /**
     * 결재 양식 삭제
     */
    public function formDestroy(int $id): bool
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $form = ApprovalForm::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($id);

        // 사용 중인 양식인지 확인
        $inUse = Approval::query()
            ->where('form_id', $id)
            ->exists();

        if ($inUse) {
            throw new BadRequestHttpException(__('error.approval.form_in_use'));
        }

        $form->deleted_by = $userId;
        $form->save();
        $form->delete();

        return true;
    }

    // =========================================================================
    // 결재선 템플릿 관리
    // =========================================================================

    /**
     * 결재선 목록
     */
    public function lineIndex(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        $query = ApprovalLine::query()
            ->where('tenant_id', $tenantId)
            ->with('creator:id,name');

        // 검색
        if (! empty($params['search'])) {
            $query->where('name', 'like', "%{$params['search']}%");
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'created_at';
        $sortDir = $params['sort_dir'] ?? 'desc';
        $query->orderBy($sortBy, $sortDir);

        $perPage = $params['per_page'] ?? 20;

        return $query->paginate($perPage);
    }

    /**
     * 결재선 상세
     */
    public function lineShow(int $id): ApprovalLine
    {
        $tenantId = $this->tenantId();

        return ApprovalLine::query()
            ->where('tenant_id', $tenantId)
            ->with('creator:id,name')
            ->findOrFail($id);
    }

    /**
     * 결재선 생성
     */
    public function lineStore(array $data): ApprovalLine
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($data, $tenantId, $userId) {
            // 기본 결재선으로 설정 시 기존 기본값 해제
            if (! empty($data['is_default'])) {
                ApprovalLine::query()
                    ->where('tenant_id', $tenantId)
                    ->where('is_default', true)
                    ->update(['is_default' => false]);
            }

            return ApprovalLine::create([
                'tenant_id' => $tenantId,
                'name' => $data['name'],
                'steps' => $data['steps'],
                'is_default' => $data['is_default'] ?? false,
                'created_by' => $userId,
                'updated_by' => $userId,
            ]);
        });
    }

    /**
     * 결재선 수정
     */
    public function lineUpdate(int $id, array $data): ApprovalLine
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $data, $tenantId, $userId) {
            $line = ApprovalLine::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            // 기본 결재선으로 설정 시 기존 기본값 해제
            if (! empty($data['is_default']) && ! $line->is_default) {
                ApprovalLine::query()
                    ->where('tenant_id', $tenantId)
                    ->where('is_default', true)
                    ->update(['is_default' => false]);
            }

            $line->fill([
                'name' => $data['name'] ?? $line->name,
                'steps' => $data['steps'] ?? $line->steps,
                'is_default' => $data['is_default'] ?? $line->is_default,
                'updated_by' => $userId,
            ]);

            $line->save();

            return $line->fresh('creator:id,name');
        });
    }

    /**
     * 결재선 삭제
     */
    public function lineDestroy(int $id): bool
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $line = ApprovalLine::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($id);

        $line->deleted_by = $userId;
        $line->save();
        $line->delete();

        return true;
    }

    // =========================================================================
    // 결재 문서 관리
    // =========================================================================

    /**
     * 기안함 - 내가 기안한 문서
     */
    public function drafts(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $query = Approval::query()
            ->where('tenant_id', $tenantId)
            ->where('drafter_id', $userId)
            ->with([
                'form:id,name,code,category',
                'drafter:id,name',
                'drafter.tenantProfile:id,user_id,position_key,department_id',
                'drafter.tenantProfile.department:id,name',
                'steps.approver:id,name',
                'steps.approver.tenantProfile:id,user_id,position_key,department_id',
                'steps.approver.tenantProfile.department:id,name',
            ]);

        // 상태 필터
        if (! empty($params['status'])) {
            $query->where('status', $params['status']);
        }

        // 검색
        if (! empty($params['search'])) {
            $query->where(function ($q) use ($params) {
                $q->where('title', 'like', "%{$params['search']}%")
                    ->orWhere('document_number', 'like', "%{$params['search']}%");
            });
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'created_at';
        $sortDir = $params['sort_dir'] ?? 'desc';
        $query->orderBy($sortBy, $sortDir);

        $perPage = $params['per_page'] ?? 20;

        return $query->paginate($perPage);
    }

    /**
     * 기안함 현황 카드
     */
    public function draftsSummary(): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $counts = Approval::query()
            ->where('tenant_id', $tenantId)
            ->where('drafter_id', $userId)
            ->selectRaw('status, COUNT(*) as count')
            ->groupBy('status')
            ->pluck('count', 'status')
            ->toArray();

        return [
            'total' => array_sum($counts),
            'draft' => $counts[Approval::STATUS_DRAFT] ?? 0,
            'pending' => $counts[Approval::STATUS_PENDING] ?? 0,
            'approved' => $counts[Approval::STATUS_APPROVED] ?? 0,
            'rejected' => $counts[Approval::STATUS_REJECTED] ?? 0,
        ];
    }

    /**
     * 결재함 - 내가 결재해야 할 문서
     */
    public function inbox(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $query = Approval::query()
            ->where('tenant_id', $tenantId)
            ->whereHas('steps', function ($q) use ($userId) {
                $q->where('approver_id', $userId)
                    ->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT]);
            })
            ->with([
                'form:id,name,code,category',
                'drafter:id,name',
                'drafter.tenantProfile:id,user_id,position_key,department_id',
                'drafter.tenantProfile.department:id,name',
                'steps' => function ($q) use ($userId) {
                    $q->where('approver_id', $userId);
                },
                'steps.approver:id,name',
                'steps.approver.tenantProfile:id,user_id,position_key,department_id',
                'steps.approver.tenantProfile.department:id,name',
            ]);

        // 상태 필터
        if (! empty($params['status'])) {
            if ($params['status'] === 'requested') {
                // 결재 요청 (현재 내 차례)
                $query->where('status', Approval::STATUS_PENDING)
                    ->whereHas('steps', function ($q) use ($userId) {
                        $q->where('approver_id', $userId)
                            ->where('status', ApprovalStep::STATUS_PENDING)
                            ->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT]);
                    });
            } elseif ($params['status'] === 'scheduled') {
                // 예정 (아직 내 차례 아님)
                $query->where('status', Approval::STATUS_PENDING)
                    ->whereHas('steps', function ($q) use ($userId) {
                        $q->where('approver_id', $userId)
                            ->where('status', ApprovalStep::STATUS_PENDING);
                    })
                    ->whereDoesntHave('steps', function ($q) use ($userId) {
                        $q->where('approver_id', $userId)
                            ->where('status', ApprovalStep::STATUS_PENDING)
                            ->whereRaw('step_order = (SELECT MIN(s2.step_order) FROM approval_steps s2 WHERE s2.approval_id = approval_steps.approval_id AND s2.status = ?)', [ApprovalStep::STATUS_PENDING]);
                    });
            } elseif ($params['status'] === 'completed') {
                // 내가 처리 완료한 문서
                $query->whereHas('steps', function ($q) use ($userId) {
                    $q->where('approver_id', $userId)
                        ->whereIn('status', [ApprovalStep::STATUS_APPROVED, ApprovalStep::STATUS_REJECTED]);
                });
            } elseif ($params['status'] === 'rejected') {
                // 내가 반려한 문서
                $query->whereHas('steps', function ($q) use ($userId) {
                    $q->where('approver_id', $userId)
                        ->where('status', ApprovalStep::STATUS_REJECTED);
                });
            }
        }

        // 날짜 범위 필터
        if (! empty($params['start_date'])) {
            $query->whereDate('created_at', '>=', $params['start_date']);
        }
        if (! empty($params['end_date'])) {
            $query->whereDate('created_at', '<=', $params['end_date']);
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'created_at';
        $sortDir = $params['sort_dir'] ?? 'desc';
        $query->orderBy($sortBy, $sortDir);

        $perPage = $params['per_page'] ?? 20;

        return $query->paginate($perPage);
    }

    /**
     * 결재함 현황 카드
     */
    public function inboxSummary(): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 결재 요청 (현재 내 차례)
        $requested = Approval::query()
            ->where('tenant_id', $tenantId)
            ->where('status', Approval::STATUS_PENDING)
            ->whereHas('steps', function ($q) use ($userId) {
                $q->where('approver_id', $userId)
                    ->where('status', ApprovalStep::STATUS_PENDING)
                    ->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT])
                    ->whereRaw('step_order = (SELECT MIN(s2.step_order) FROM approval_steps s2 WHERE s2.approval_id = approval_steps.approval_id AND s2.status = ?)', [ApprovalStep::STATUS_PENDING]);
            })
            ->count();

        // 예정 (내 차례 대기중)
        $scheduled = ApprovalStep::query()
            ->where('approver_id', $userId)
            ->where('status', ApprovalStep::STATUS_PENDING)
            ->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT])
            ->whereHas('approval', function ($q) use ($tenantId) {
                $q->where('tenant_id', $tenantId)
                    ->where('status', Approval::STATUS_PENDING);
            })
            ->count() - $requested;

        // 완료 (내가 처리한 문서)
        $completed = ApprovalStep::query()
            ->where('approver_id', $userId)
            ->whereIn('status', [ApprovalStep::STATUS_APPROVED, ApprovalStep::STATUS_REJECTED])
            ->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT])
            ->whereHas('approval', function ($q) use ($tenantId) {
                $q->where('tenant_id', $tenantId);
            })
            ->count();

        // 반려 (내가 반려한 문서)
        $rejected = ApprovalStep::query()
            ->where('approver_id', $userId)
            ->where('status', ApprovalStep::STATUS_REJECTED)
            ->whereHas('approval', function ($q) use ($tenantId) {
                $q->where('tenant_id', $tenantId);
            })
            ->count();

        return [
            'requested' => max(0, $requested),
            'scheduled' => max(0, $scheduled),
            'completed' => $completed,
            'rejected' => $rejected,
        ];
    }

    /**
     * 참조함 - 내가 참조된 문서
     */
    public function reference(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $query = Approval::query()
            ->where('tenant_id', $tenantId)
            ->whereHas('steps', function ($q) use ($userId) {
                $q->where('approver_id', $userId)
                    ->where('step_type', ApprovalLine::STEP_TYPE_REFERENCE);
            })
            ->with(['form:id,name,code,category', 'drafter:id,name', 'steps' => function ($q) use ($userId) {
                $q->where('approver_id', $userId)
                    ->where('step_type', ApprovalLine::STEP_TYPE_REFERENCE);
            }]);

        // 열람 상태 필터
        if (isset($params['is_read'])) {
            $query->whereHas('steps', function ($q) use ($userId, $params) {
                $q->where('approver_id', $userId)
                    ->where('step_type', ApprovalLine::STEP_TYPE_REFERENCE)
                    ->where('is_read', $params['is_read']);
            });
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'created_at';
        $sortDir = $params['sort_dir'] ?? 'desc';
        $query->orderBy($sortBy, $sortDir);

        $perPage = $params['per_page'] ?? 20;

        return $query->paginate($perPage);
    }

    /**
     * 결재 문서 상세
     */
    public function show(int $id): Approval
    {
        $tenantId = $this->tenantId();

        $approval = Approval::query()
            ->where('tenant_id', $tenantId)
            ->with([
                'form:id,name,code,category,template',
                'drafter:id,name,email',
                'drafter.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'drafter.tenantProfile.department:id,name',
                'steps.approver:id,name,email',
                'steps.approver.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'steps.approver.tenantProfile.department:id,name',
            ])
            ->findOrFail($id);

        // Document 브릿지: 연결된 문서 데이터 로딩
        if ($approval->linkable_type === Document::class) {
            $approval->load([
                'linkable.template',
                'linkable.template.approvalLines',
                'linkable.data',
                'linkable.approvals.user:id,name',
                'linkable.attachments',
            ]);
        }

        return $approval;
    }

    /**
     * 결재 문서 생성 (임시저장 또는 상신)
     */
    public function store(array $data): Approval
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($data, $tenantId, $userId) {
            // 양식 확인 (form_id 또는 form_code 지원)
            $formQuery = ApprovalForm::query()
                ->where('tenant_id', $tenantId)
                ->active();

            if (! empty($data['form_id'])) {
                $form = $formQuery->where('id', $data['form_id'])->firstOrFail();
            } elseif (! empty($data['form_code'])) {
                $form = $formQuery->where('code', $data['form_code'])->firstOrFail();
            } else {
                throw new BadRequestHttpException(__('error.approval.form_required'));
            }

            // 문서번호 생성
            $documentNumber = $this->generateDocumentNumber($tenantId);

            $status = ! empty($data['submit']) ? Approval::STATUS_PENDING : Approval::STATUS_DRAFT;

            $approval = Approval::create([
                'tenant_id' => $tenantId,
                'document_number' => $documentNumber,
                'form_id' => $form->id,
                'title' => $data['title'],
                'content' => $data['content'],
                'status' => $status,
                'drafter_id' => $userId,
                'drafted_at' => $status === Approval::STATUS_PENDING ? now() : null,
                'attachments' => $data['attachments'] ?? null,
                'created_by' => $userId,
                'updated_by' => $userId,
            ]);

            // 결재선 생성 (steps가 있으면 항상 저장)
            if (! empty($data['steps'])) {
                $this->createApprovalSteps($approval, $data['steps']);
            }

            return $approval->fresh([
                'form:id,name,code,category',
                'drafter:id,name',
                'drafter.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'drafter.tenantProfile.department:id,name',
                'steps.approver:id,name',
                'steps.approver.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'steps.approver.tenantProfile.department:id,name',
            ]);
        });
    }

    /**
     * 결재 문서 수정 (임시저장 상태만)
     */
    public function update(int $id, array $data): Approval
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $data, $tenantId, $userId) {
            $approval = Approval::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            if (! $approval->isEditable()) {
                throw new BadRequestHttpException(__('error.approval.not_editable'));
            }

            // form_id 또는 form_code로 양식 ID 결정
            $formId = $approval->form_id;
            if (! empty($data['form_id'])) {
                $formId = $data['form_id'];
            } elseif (! empty($data['form_code'])) {
                $form = ApprovalForm::query()
                    ->where('tenant_id', $tenantId)
                    ->where('code', $data['form_code'])
                    ->active()
                    ->first();
                if ($form) {
                    $formId = $form->id;
                }
            }

            $approval->fill([
                'form_id' => $formId,
                'title' => $data['title'] ?? $approval->title,
                'content' => $data['content'] ?? $approval->content,
                'attachments' => $data['attachments'] ?? $approval->attachments,
                'updated_by' => $userId,
            ]);

            $approval->save();

            // 결재선 수정 (steps가 전달된 경우)
            if (! empty($data['steps'])) {
                // 기존 결재선 삭제 후 새로 생성
                $approval->steps()->delete();
                $this->createApprovalSteps($approval, $data['steps']);
            }

            return $approval->fresh([
                'form:id,name,code,category',
                'drafter:id,name',
                'drafter.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'drafter.tenantProfile.department:id,name',
                'steps.approver:id,name',
                'steps.approver.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'steps.approver.tenantProfile.department:id,name',
            ]);
        });
    }

    /**
     * 결재 문서 삭제 (임시저장 상태만)
     */
    public function destroy(int $id): bool
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $tenantId, $userId) {
            $approval = Approval::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            if (! $approval->isDeletable()) {
                throw new BadRequestHttpException(__('error.approval.not_deletable'));
            }

            $approval->deleted_by = $userId;
            $approval->save();
            $approval->delete();

            return true;
        });
    }

    /**
     * 결재 상신
     */
    public function submit(int $id, array $data): Approval
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $data, $tenantId, $userId) {
            $approval = Approval::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            if (! $approval->isSubmittable()) {
                throw new BadRequestHttpException(__('error.approval.not_submittable'));
            }

            // 기존 결재선 확인 (steps 없이 상신하는 경우)
            if (empty($data['steps'])) {
                $existingSteps = $approval->steps()
                    ->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT])
                    ->count();

                if ($existingSteps === 0) {
                    throw new BadRequestHttpException(__('error.approval.steps_required'));
                }
            }

            // 먼저 approval을 pending으로 변경 (Observer가 올바른 상태로 트리거되도록)
            $approval->status = Approval::STATUS_PENDING;
            $approval->drafted_at = now();
            $approval->current_step = 1;
            $approval->updated_by = $userId;
            $approval->save();

            // steps가 있으면 새로 생성 (approval이 pending 상태일 때 생성해야 알림 발송)
            if (! empty($data['steps'])) {
                // 기존 결재선 삭제 후 새로 생성
                $approval->steps()->delete();
                $this->createApprovalSteps($approval, $data['steps']);
            } else {
                // 기존 결재선 사용 시, Observer가 트리거되지 않으므로 수동으로 알림 발송
                $firstPendingStep = $approval->steps()
                    ->where('status', ApprovalStep::STATUS_PENDING)
                    ->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT])
                    ->orderBy('step_order')
                    ->first();

                if ($firstPendingStep) {
                    $this->todayIssueService->handleApprovalStepChange($firstPendingStep);
                }
            }

            return $approval->fresh([
                'form:id,name,code,category',
                'drafter:id,name',
                'drafter.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'drafter.tenantProfile.department:id,name',
                'steps.approver:id,name',
                'steps.approver.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'steps.approver.tenantProfile.department:id,name',
            ]);
        });
    }

    /**
     * 결재 승인
     */
    public function approve(int $id, ?string $comment = null): Approval
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $comment, $tenantId, $userId) {
            $approval = Approval::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            if (! $approval->isActionable()) {
                throw new BadRequestHttpException(__('error.approval.not_actionable'));
            }

            // 현재 내 결재 단계 찾기
            $myStep = $approval->steps()
                ->where('approver_id', $userId)
                ->where('status', ApprovalStep::STATUS_PENDING)
                ->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT])
                ->orderBy('step_order')
                ->first();

            if (! $myStep) {
                throw new BadRequestHttpException(__('error.approval.not_your_turn'));
            }

            // 내 단계 승인
            $myStep->status = ApprovalStep::STATUS_APPROVED;
            $myStep->comment = $comment;
            $myStep->acted_at = now();
            $myStep->save();

            // 다음 결재자 확인
            $nextStep = $approval->steps()
                ->where('status', ApprovalStep::STATUS_PENDING)
                ->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT])
                ->orderBy('step_order')
                ->first();

            if (! $nextStep) {
                // 모든 결재 완료
                $approval->status = Approval::STATUS_APPROVED;
                $approval->completed_at = now();
            }

            $approval->current_step = $myStep->step_order + 1;
            $approval->updated_by = $userId;
            $approval->save();

            // Document 브릿지 동기화
            $this->syncToLinkedDocument($approval);

            return $approval->fresh([
                'form:id,name,code,category',
                'drafter:id,name',
                'drafter.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'drafter.tenantProfile.department:id,name',
                'steps.approver:id,name',
                'steps.approver.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'steps.approver.tenantProfile.department:id,name',
            ]);
        });
    }

    /**
     * 결재 반려
     */
    public function reject(int $id, string $comment): Approval
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $comment, $tenantId, $userId) {
            $approval = Approval::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            if (! $approval->isActionable()) {
                throw new BadRequestHttpException(__('error.approval.not_actionable'));
            }

            // 현재 내 결재 단계 찾기
            $myStep = $approval->steps()
                ->where('approver_id', $userId)
                ->where('status', ApprovalStep::STATUS_PENDING)
                ->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT])
                ->orderBy('step_order')
                ->first();

            if (! $myStep) {
                throw new BadRequestHttpException(__('error.approval.not_your_turn'));
            }

            // 반려 처리
            $myStep->status = ApprovalStep::STATUS_REJECTED;
            $myStep->comment = $comment;
            $myStep->acted_at = now();
            $myStep->save();

            // 문서 반려 상태로 변경
            $approval->status = Approval::STATUS_REJECTED;
            $approval->completed_at = now();
            $approval->updated_by = $userId;
            $approval->save();

            // Document 브릿지 동기화
            $this->syncToLinkedDocument($approval);

            return $approval->fresh([
                'form:id,name,code,category',
                'drafter:id,name',
                'drafter.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'drafter.tenantProfile.department:id,name',
                'steps.approver:id,name',
                'steps.approver.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
                'steps.approver.tenantProfile.department:id,name',
            ]);
        });
    }

    /**
     * 결재 회수 (기안자만)
     */
    public function cancel(int $id): Approval
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $tenantId, $userId) {
            $approval = Approval::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            if (! $approval->isCancellable()) {
                throw new BadRequestHttpException(__('error.approval.not_cancellable'));
            }

            // 기안자만 회수 가능
            if ($approval->drafter_id !== $userId) {
                throw new BadRequestHttpException(__('error.approval.only_drafter_can_cancel'));
            }

            $approval->status = Approval::STATUS_CANCELLED;
            $approval->completed_at = now();
            $approval->updated_by = $userId;
            $approval->save();

            // Document 브릿지 동기화 (steps 삭제 전에 실행)
            $this->syncToLinkedDocument($approval);

            // 결재 단계들 삭제
            $approval->steps()->delete();

            return $approval->fresh([
                'form:id,name,code,category',
                'drafter:id,name',
            ]);
        });
    }

    /**
     * Approval → Document 브릿지 동기화
     * 결재 승인/반려/회수 시 연결된 Document의 상태와 결재란을 동기화
     */
    private function syncToLinkedDocument(Approval $approval): void
    {
        if ($approval->linkable_type !== Document::class) {
            return;
        }

        $document = Document::find($approval->linkable_id);
        if (! $document) {
            return;
        }

        // approval_steps → document_approvals 동기화 (승인자 이름/시각 반영)
        foreach ($approval->steps as $step) {
            if ($step->status === ApprovalStep::STATUS_PENDING) {
                continue;
            }

            $docApproval = $document->approvals()
                ->where('step', $step->step_order)
                ->first();

            if ($docApproval) {
                $docApproval->update([
                    'status' => strtoupper($step->status),
                    'acted_at' => $step->acted_at,
                    'comment' => $step->comment,
                ]);
            }
        }

        // Document 전체 상태 동기화
        $documentStatus = match ($approval->status) {
            Approval::STATUS_APPROVED => Document::STATUS_APPROVED,
            Approval::STATUS_REJECTED => Document::STATUS_REJECTED,
            Approval::STATUS_CANCELLED => Document::STATUS_CANCELLED,
            default => Document::STATUS_PENDING,
        };

        $document->update([
            'status' => $documentStatus,
            'completed_at' => in_array($approval->status, [
                Approval::STATUS_APPROVED,
                Approval::STATUS_REJECTED,
            ]) ? now() : null,
        ]);
    }

    /**
     * 참조 열람 처리
     */
    public function markRead(int $id): Approval
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $approval = Approval::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($id);

        $step = $approval->steps()
            ->where('approver_id', $userId)
            ->where('step_type', ApprovalLine::STEP_TYPE_REFERENCE)
            ->first();

        if (! $step) {
            throw new NotFoundHttpException(__('error.approval.not_referee'));
        }

        $step->is_read = true;
        $step->read_at = now();
        $step->save();

        return $approval->fresh([
            'form:id,name,code,category',
            'drafter:id,name',
            'drafter.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
            'drafter.tenantProfile.department:id,name',
            'steps.approver:id,name',
            'steps.approver.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
            'steps.approver.tenantProfile.department:id,name',
        ]);
    }

    /**
     * 참조 미열람 처리
     */
    public function markUnread(int $id): Approval
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $approval = Approval::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($id);

        $step = $approval->steps()
            ->where('approver_id', $userId)
            ->where('step_type', ApprovalLine::STEP_TYPE_REFERENCE)
            ->first();

        if (! $step) {
            throw new NotFoundHttpException(__('error.approval.not_referee'));
        }

        $step->is_read = false;
        $step->read_at = null;
        $step->save();

        return $approval->fresh([
            'form:id,name,code,category',
            'drafter:id,name',
            'drafter.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
            'drafter.tenantProfile.department:id,name',
            'steps.approver:id,name',
            'steps.approver.tenantProfile:id,user_id,tenant_id,department_id,position_key,display_name',
            'steps.approver.tenantProfile.department:id,name',
        ]);
    }

    // =========================================================================
    // 헬퍼 메서드
    // =========================================================================

    /**
     * 문서번호 생성
     */
    private function generateDocumentNumber(int $tenantId): string
    {
        $prefix = 'AP';
        $date = now()->format('Ymd');

        $lastNumber = Approval::query()
            ->where('tenant_id', $tenantId)
            ->where('document_number', 'like', "{$prefix}-{$date}-%")
            ->orderByDesc('document_number')
            ->value('document_number');

        if ($lastNumber) {
            $sequence = (int) substr($lastNumber, -4) + 1;
        } else {
            $sequence = 1;
        }

        return sprintf('%s-%s-%04d', $prefix, $date, $sequence);
    }

    /**
     * 결재 단계 생성
     * 프론트엔드 호환성: step_type/approver_id 또는 type/user_id 지원
     * 중복 결재자 자동 제거
     */
    private function createApprovalSteps(Approval $approval, array $steps): void
    {
        $order = 1;
        $processedApprovers = []; // 중복 체크용

        foreach ($steps as $step) {
            // 필드명 호환성: step_type 또는 type
            $stepType = $step['step_type'] ?? $step['type'] ?? null;
            // 필드명 호환성: approver_id 또는 user_id
            $approverId = $step['approver_id'] ?? $step['user_id'] ?? null;
            // step_order가 있으면 사용, 없으면 자동 증가
            $stepOrder = $step['step_order'] ?? $order++;

            if ($stepType && $approverId) {
                // 동일 결재자 중복 건너뛰기
                if (in_array($approverId, $processedApprovers, true)) {
                    continue;
                }
                $processedApprovers[] = $approverId;

                ApprovalStep::create([
                    'approval_id' => $approval->id,
                    'step_order' => $stepOrder,
                    'step_type' => $stepType,
                    'approver_id' => $approverId,
                    'status' => ApprovalStep::STATUS_PENDING,
                ]);
            }
        }
    }
}
