<?php

namespace App\Services;

use App\Models\BadDebts\BadDebt;
use App\Models\BadDebts\BadDebtDocument;
use App\Models\BadDebts\BadDebtMemo;
use App\Models\Orders\Client;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

class BadDebtService extends Service
{
    /**
     * 악성채권 목록 조회 (거래처 기준)
     *
     * 거래처별로 is_active=true인 악성채권을 집계하여 조회
     */
    public function index(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        $query = Client::query()
            ->where('tenant_id', $tenantId)
            // is_active=true인 악성채권이 있는 거래처만
            ->whereHas('badDebts', function ($q) {
                $q->where('is_active', true);
            })
            // 활성 악성채권 eager loading (추심중/법적조치 + is_active=true)
            ->with(['activeBadDebts' => function ($q) {
                $q->with('assignedUser:id,name')
                    ->orderBy('created_at', 'desc');
            }])
            // 집계: 총 미수금액 (is_active=true인 건만)
            ->withSum(['badDebts as total_debt_amount' => function ($q) {
                $q->where('is_active', true);
            }], 'debt_amount')
            // 집계: 최대 연체일수 (is_active=true인 건만)
            ->withMax(['badDebts as max_overdue_days' => function ($q) {
                $q->where('is_active', true);
            }], 'overdue_days')
            // 집계: 악성채권 건수 (is_active=true인 건만)
            ->withCount(['badDebts as active_bad_debt_count' => function ($q) {
                $q->where('is_active', true);
            }]);

        // 거래처 필터
        if (! empty($params['client_id'])) {
            $query->where('id', $params['client_id']);
        }

        // 상태 필터 (해당 상태의 악성채권이 있는 거래처만)
        if (! empty($params['status'])) {
            $query->whereHas('badDebts', function ($q) use ($params) {
                $q->where('is_active', true)
                    ->where('status', $params['status']);
            });
        }

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

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

        // 페이지네이션
        $perPage = $params['per_page'] ?? 20;

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

    /**
     * 악성채권 요약 통계 (is_active=true인 건만)
     */
    public function summary(array $params = []): array
    {
        $tenantId = $this->tenantId();

        // is_active=true인 악성채권만 통계
        $query = BadDebt::query()
            ->where('tenant_id', $tenantId)
            ->where('is_active', true);

        // 거래처 필터
        if (! empty($params['client_id'])) {
            $query->where('client_id', $params['client_id']);
        }

        // 전체 합계
        $totalAmount = (clone $query)->sum('debt_amount');

        // 상태별 합계
        $collectingAmount = (clone $query)->collecting()->sum('debt_amount');
        $legalActionAmount = (clone $query)->legalAction()->sum('debt_amount');
        $recoveredAmount = (clone $query)->recovered()->sum('debt_amount');
        $badDebtAmount = (clone $query)->badDebt()->sum('debt_amount');

        // 거래처 수 (is_active=true인 악성채권이 있는)
        $clientCount = BadDebt::query()
            ->where('tenant_id', $tenantId)
            ->where('is_active', true)
            ->distinct('client_id')
            ->count('client_id');

        return [
            'total_amount' => (float) $totalAmount,
            'collecting_amount' => (float) $collectingAmount,
            'legal_action_amount' => (float) $legalActionAmount,
            'recovered_amount' => (float) $recoveredAmount,
            'bad_debt_amount' => (float) $badDebtAmount,
            'client_count' => $clientCount,
        ];
    }

    /**
     * 악성채권 상세 조회
     */
    public function show(int $id): BadDebt
    {
        $tenantId = $this->tenantId();

        return BadDebt::query()
            ->where('tenant_id', $tenantId)
            ->with([
                'client',
                'assignedUser:id,name',
                'creator:id,name',
                'documents.file',
                'memos.creator:id,name',
            ])
            ->findOrFail($id);
    }

    /**
     * 악성채권 등록
     */
    public function store(array $data): BadDebt
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($data, $tenantId, $userId) {
            $badDebt = new BadDebt;
            $badDebt->tenant_id = $tenantId;
            $badDebt->client_id = $data['client_id'];
            $badDebt->debt_amount = $data['debt_amount'];
            $badDebt->status = $data['status'] ?? BadDebt::STATUS_COLLECTING;
            $badDebt->overdue_days = $data['overdue_days'] ?? 0;
            $badDebt->assigned_user_id = $data['assigned_user_id'] ?? null;
            $badDebt->occurred_at = $data['occurred_at'] ?? null;
            $badDebt->closed_at = $data['closed_at'] ?? null;
            $badDebt->is_active = $data['is_active'] ?? true;
            $badDebt->options = $data['options'] ?? null;
            $badDebt->created_by = $userId;
            $badDebt->updated_by = $userId;
            $badDebt->save();

            return $badDebt->load(['client:id,name,client_code', 'assignedUser:id,name']);
        });
    }

    /**
     * 악성채권 수정
     */
    public function update(int $id, array $data): BadDebt
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

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

            if (isset($data['client_id'])) {
                $badDebt->client_id = $data['client_id'];
            }
            if (isset($data['debt_amount'])) {
                $badDebt->debt_amount = $data['debt_amount'];
            }
            if (isset($data['status'])) {
                $badDebt->status = $data['status'];
            }
            if (isset($data['overdue_days'])) {
                $badDebt->overdue_days = $data['overdue_days'];
            }
            if (array_key_exists('assigned_user_id', $data)) {
                $badDebt->assigned_user_id = $data['assigned_user_id'];
            }
            if (array_key_exists('occurred_at', $data)) {
                $badDebt->occurred_at = $data['occurred_at'];
            }
            if (array_key_exists('closed_at', $data)) {
                $badDebt->closed_at = $data['closed_at'];
            }
            if (isset($data['is_active'])) {
                $badDebt->is_active = $data['is_active'];
            }
            if (array_key_exists('options', $data)) {
                $badDebt->options = $data['options'];
            }

            $badDebt->updated_by = $userId;
            $badDebt->save();

            return $badDebt->fresh(['client:id,name,client_code', 'assignedUser:id,name']);
        });
    }

    /**
     * 악성채권 삭제
     */
    public function destroy(int $id): bool
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

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

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

            return true;
        });
    }

    /**
     * 설정 토글 (is_active)
     */
    public function toggle(int $id): BadDebt
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

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

            $badDebt->is_active = ! $badDebt->is_active;
            $badDebt->updated_by = $userId;
            $badDebt->save();

            return $badDebt->fresh(['client:id,name,client_code', 'assignedUser:id,name']);
        });
    }

    /**
     * 서류 첨부
     */
    public function addDocument(int $id, array $data): BadDebtDocument
    {
        $tenantId = $this->tenantId();

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

        $document = new BadDebtDocument;
        $document->bad_debt_id = $badDebt->id;
        $document->document_type = $data['document_type'];
        $document->file_id = $data['file_id'];
        $document->save();

        return $document->load('file');
    }

    /**
     * 서류 삭제
     */
    public function removeDocument(int $id, int $documentId): bool
    {
        $tenantId = $this->tenantId();

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

        $document = BadDebtDocument::query()
            ->where('bad_debt_id', $badDebt->id)
            ->findOrFail($documentId);

        return $document->delete();
    }

    /**
     * 메모 추가
     */
    public function addMemo(int $id, array $data): BadDebtMemo
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

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

        $memo = new BadDebtMemo;
        $memo->bad_debt_id = $badDebt->id;
        $memo->content = $data['content'];
        $memo->created_by = $userId;
        $memo->save();

        return $memo->load('creator:id,name');
    }

    /**
     * 메모 삭제
     */
    public function removeMemo(int $id, int $memoId): bool
    {
        $tenantId = $this->tenantId();

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

        $memo = BadDebtMemo::query()
            ->where('bad_debt_id', $badDebt->id)
            ->findOrFail($memoId);

        return $memo->delete();
    }
}
