<?php

namespace App\Services;

use App\Models\BadDebts\BadDebt;
use App\Models\Orders\Client;
use App\Models\Tenants\Deposit;
use App\Models\Tenants\Sale;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class ClientService extends Service
{
    /** 목록(검색/페이징) */
    public function index(array $params)
    {
        $tenantId = $this->tenantId();

        $page = (int) ($params['page'] ?? 1);
        $size = (int) ($params['size'] ?? 20);
        $q = trim((string) ($params['q'] ?? ''));
        $onlyActive = $params['only_active'] ?? null;
        $clientType = $params['client_type'] ?? null;
        $startDate = $params['start_date'] ?? null;
        $endDate = $params['end_date'] ?? null;

        $query = Client::query()->where('tenant_id', $tenantId);

        if ($q !== '') {
            $query->where(function ($qq) use ($q) {
                $qq->where('name', 'like', "%{$q}%")
                    ->orWhere('client_code', 'like', "%{$q}%")
                    ->orWhere('contact_person', 'like', "%{$q}%");
            });
        }

        if ($onlyActive !== null) {
            $query->where('is_active', (bool) $onlyActive);
        }

        // 거래처 유형 필터 (쉼표 구분 복수 값 지원: PURCHASE,BOTH)
        if ($clientType !== null && $clientType !== '') {
            $types = array_map('trim', explode(',', $clientType));
            $query->whereIn('client_type', $types);
        }

        // 등록일 기간 필터
        if ($startDate) {
            $query->whereDate('created_at', '>=', $startDate);
        }
        if ($endDate) {
            $query->whereDate('created_at', '<=', $endDate);
        }

        $query->orderBy('client_code')->orderBy('id');

        $paginator = $query->paginate($size, ['*'], 'page', $page);

        // 미수금 계산: 매출 합계 - 입금 합계
        $clientIds = $paginator->pluck('id')->toArray();

        if (! empty($clientIds)) {
            // 거래처별 매출 합계
            $salesByClient = Sale::where('tenant_id', $tenantId)
                ->whereIn('client_id', $clientIds)
                ->whereNull('deleted_at')
                ->groupBy('client_id')
                ->select('client_id', DB::raw('SUM(total_amount) as total_sales'))
                ->pluck('total_sales', 'client_id');

            // 거래처별 입금 합계
            $depositsByClient = Deposit::where('tenant_id', $tenantId)
                ->whereIn('client_id', $clientIds)
                ->whereNull('deleted_at')
                ->groupBy('client_id')
                ->select('client_id', DB::raw('SUM(amount) as total_deposits'))
                ->pluck('total_deposits', 'client_id');

            // 거래처별 활성 악성채권 합계 (추심중, 법적조치)
            $badDebtsByClient = BadDebt::where('tenant_id', $tenantId)
                ->whereIn('client_id', $clientIds)
                ->whereIn('status', [BadDebt::STATUS_COLLECTING, BadDebt::STATUS_LEGAL_ACTION])
                ->where('is_active', true)
                ->whereNull('deleted_at')
                ->groupBy('client_id')
                ->select('client_id', DB::raw('SUM(debt_amount) as total_bad_debt'))
                ->pluck('total_bad_debt', 'client_id');

            // 활성 악성채권이 있는 거래처 ID 목록 (금액과 무관하게 레코드 존재 여부)
            $clientsWithBadDebt = BadDebt::where('tenant_id', $tenantId)
                ->whereIn('client_id', $clientIds)
                ->whereIn('status', [BadDebt::STATUS_COLLECTING, BadDebt::STATUS_LEGAL_ACTION])
                ->where('is_active', true)
                ->whereNull('deleted_at')
                ->distinct()
                ->pluck('client_id')
                ->flip()
                ->toArray();

            // 각 거래처에 미수금/악성채권 정보 추가
            $paginator->getCollection()->transform(function ($client) use ($salesByClient, $depositsByClient, $badDebtsByClient, $clientsWithBadDebt) {
                $totalSales = $salesByClient[$client->id] ?? 0;
                $totalDeposits = $depositsByClient[$client->id] ?? 0;
                $client->outstanding_amount = max(0, $totalSales - $totalDeposits);
                $client->bad_debt_total = $badDebtsByClient[$client->id] ?? 0;
                $client->has_bad_debt = isset($clientsWithBadDebt[$client->id]);

                return $client;
            });
        }

        return $paginator;
    }

    /** 단건 */
    public function show(int $id)
    {
        $tenantId = $this->tenantId();
        $client = Client::where('tenant_id', $tenantId)->find($id);
        if (! $client) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        // 미수금 계산
        $totalSales = Sale::where('tenant_id', $tenantId)
            ->where('client_id', $id)
            ->whereNull('deleted_at')
            ->sum('total_amount');

        $totalDeposits = Deposit::where('tenant_id', $tenantId)
            ->where('client_id', $id)
            ->whereNull('deleted_at')
            ->sum('amount');

        $client->outstanding_amount = max(0, $totalSales - $totalDeposits);

        // 악성채권 정보
        $activeBadDebtQuery = BadDebt::where('tenant_id', $tenantId)
            ->where('client_id', $id)
            ->whereIn('status', [BadDebt::STATUS_COLLECTING, BadDebt::STATUS_LEGAL_ACTION])
            ->where('is_active', true)
            ->whereNull('deleted_at');

        $client->bad_debt_total = (clone $activeBadDebtQuery)->sum('debt_amount');
        $client->has_bad_debt = (clone $activeBadDebtQuery)->exists();

        return $client;
    }

    /** 생성 */
    public function store(array $data)
    {
        $tenantId = $this->tenantId();

        // client_code 자동 생성 (프론트에서 보내도 무시)
        $data['client_code'] = $this->generateClientCode($tenantId);

        $data['tenant_id'] = $tenantId;
        $data['is_active'] = $data['is_active'] ?? true;

        $client = Client::create($data);

        // 신규 거래처 등록 푸시는 ClientIssueObserver가 자동 처리

        return $client;
    }

    /**
     * 유니크한 client_code 자동 생성
     * 형식: 8자리 영숫자 (예: A3B7X9K2)
     */
    private function generateClientCode(int $tenantId): string
    {
        $maxAttempts = 10;
        $attempt = 0;

        do {
            // 8자리 영숫자 코드 생성 (대문자 + 숫자)
            $code = strtoupper(substr(bin2hex(random_bytes(4)), 0, 8));

            // 중복 검사
            $exists = Client::withoutGlobalScopes()
                ->where('tenant_id', $tenantId)
                ->where('client_code', $code)
                ->exists();

            $attempt++;
        } while ($exists && $attempt < $maxAttempts);

        if ($exists) {
            // 극히 드문 경우: timestamp 추가하여 유니크성 보장
            $code = strtoupper(substr(bin2hex(random_bytes(2)), 0, 4).dechex(time() % 0xFFFF));
        }

        return $code;
    }

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

        $client = Client::where('tenant_id', $tenantId)->find($id);
        if (! $client) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        // client_code 변경 불가 (프론트에서 보내도 무시)
        unset($data['client_code']);

        // bad_debt 토글 처리 (bad_debts 테이블과 연동)
        $badDebtToggle = $data['bad_debt'] ?? null;
        unset($data['bad_debt']); // Client 모델에는 bad_debt 컬럼이 없으므로 제거

        $client->update($data);

        // bad_debt 토글이 명시적으로 전달된 경우에만 처리
        if ($badDebtToggle !== null) {
            $this->syncBadDebtStatus($client, (bool) $badDebtToggle, $userId);
        }

        return $client->refresh();
    }

    /**
     * 악성채권 상태 동기화
     * 프론트엔드의 bad_debt 토글에 따라 bad_debts 테이블 연동
     */
    private function syncBadDebtStatus(Client $client, bool $hasBadDebt, ?int $userId): void
    {
        $tenantId = $client->tenant_id;

        // 현재 활성 악성채권 조회
        $activeBadDebt = BadDebt::where('tenant_id', $tenantId)
            ->where('client_id', $client->id)
            ->where('is_active', true)
            ->whereIn('status', [BadDebt::STATUS_COLLECTING, BadDebt::STATUS_LEGAL_ACTION])
            ->first();

        if ($hasBadDebt && ! $activeBadDebt) {
            // 악성채권 활성화: 새 레코드 생성
            BadDebt::create([
                'tenant_id' => $tenantId,
                'client_id' => $client->id,
                'debt_amount' => $client->outstanding_balance ?? 0,
                'status' => BadDebt::STATUS_COLLECTING,
                'overdue_days' => 0,
                'occurred_at' => now(),
                'is_active' => true,
                'created_by' => $userId,
            ]);
        } elseif (! $hasBadDebt && $activeBadDebt) {
            // 악성채권 비활성화: 기존 레코드 종료 처리
            $activeBadDebt->update([
                'is_active' => false,
                'status' => BadDebt::STATUS_RECOVERED,
                'closed_at' => now(),
                'updated_by' => $userId,
            ]);
        }
    }

    /** 삭제 */
    public function destroy(int $id)
    {
        $tenantId = $this->tenantId();

        $client = Client::where('tenant_id', $tenantId)->find($id);
        if (! $client) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        // 주문 존재 검사
        if ($client->orders()->exists()) {
            throw new BadRequestHttpException(__('error.has_orders'));
        }

        $client->delete();

        return 'success';
    }

    /** 활성/비활성 토글 */
    public function toggle(int $id)
    {
        $tenantId = $this->tenantId();
        $client = Client::where('tenant_id', $tenantId)->find($id);
        if (! $client) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        $client->is_active = ! $client->is_active;
        $client->save();

        return $client->refresh();
    }

    /**
     * 거래처 통계 조회
     */
    public function stats(): array
    {
        $tenantId = $this->tenantId();

        $total = Client::where('tenant_id', $tenantId)->count();

        // 거래처 유형별 통계
        $typeCounts = Client::where('tenant_id', $tenantId)
            ->selectRaw('client_type, COUNT(*) as count')
            ->groupBy('client_type')
            ->pluck('count', 'client_type')
            ->toArray();

        // 악성채권 보유 거래처 수 (활성 악성채권이 있는 거래처)
        $badDebtClientIds = BadDebt::where('tenant_id', $tenantId)
            ->whereIn('status', [BadDebt::STATUS_COLLECTING, BadDebt::STATUS_LEGAL_ACTION])
            ->where('is_active', true)
            ->whereNull('deleted_at')
            ->distinct('client_id')
            ->pluck('client_id');

        $badDebtCount = Client::where('tenant_id', $tenantId)
            ->whereIn('id', $badDebtClientIds)
            ->count();

        return [
            'total' => $total,
            'sales' => $typeCounts['SALES'] ?? 0,
            'purchase' => $typeCounts['PURCHASE'] ?? 0,
            'both' => $typeCounts['BOTH'] ?? 0,
            'badDebt' => $badDebtCount,
            'normal' => $total - $badDebtCount,
        ];
    }

    /**
     * 거래처 일괄 삭제
     */
    public function bulkDestroy(array $ids): int
    {
        $tenantId = $this->tenantId();

        $clients = Client::where('tenant_id', $tenantId)
            ->whereIn('id', $ids)
            ->get();

        $deletedCount = 0;
        foreach ($clients as $client) {
            // 주문 존재 검사 - 주문 있으면 건너뛰기
            if ($client->orders()->exists()) {
                continue;
            }

            $client->delete();
            $deletedCount++;
        }

        return $deletedCount;
    }
}
