<?php

namespace App\Services;

use App\Models\Tenants\BankAccount;
use App\Models\Tenants\Deposit;
use App\Models\Tenants\Withdrawal;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

/**
 * 은행 거래 (입출금 통합) 조회 서비스
 */
class BankTransactionService extends Service
{
    /**
     * 입출금 통합 목록 조회
     */
    public function index(array $params): LengthAwarePaginator
    {
        $perPage = $params['per_page'] ?? 20;
        $page = $params['page'] ?? 1;
        $startDate = $params['start_date'] ?? null;
        $endDate = $params['end_date'] ?? null;
        $bankAccountId = $params['bank_account_id'] ?? null;
        $transactionType = $params['transaction_type'] ?? null;
        $search = $params['search'] ?? null;
        $sortBy = $params['sort_by'] ?? 'transaction_date';
        $sortDir = $params['sort_dir'] ?? 'desc';

        $tenantId = $this->tenantId();

        // 입금 쿼리 (payment_method = 'transfer')
        $depositsQuery = DB::table('deposits')
            ->leftJoin('bank_accounts', 'deposits.bank_account_id', '=', 'bank_accounts.id')
            ->leftJoin('clients', 'deposits.client_id', '=', 'clients.id')
            ->where('deposits.tenant_id', $tenantId)
            ->where('deposits.payment_method', 'transfer')
            ->whereNull('deposits.deleted_at')
            ->select([
                'deposits.id',
                DB::raw("'deposit' as type"),
                'deposits.deposit_date as transaction_date',
                'bank_accounts.id as bank_account_id',
                'bank_accounts.bank_name',
                'bank_accounts.account_name',
                'deposits.description as note',
                'deposits.client_id as vendor_id',
                DB::raw('COALESCE(clients.name, deposits.client_name) as vendor_name'),
                'deposits.client_name as depositor_name',
                'deposits.amount as deposit_amount',
                DB::raw('0 as withdrawal_amount'),
                'deposits.account_code as transaction_type',
                DB::raw("CONCAT('deposit-', deposits.id) as source_id"),
                'deposits.created_at',
                'deposits.updated_at',
            ]);

        // 출금 쿼리 (payment_method = 'transfer')
        $withdrawalsQuery = DB::table('withdrawals')
            ->leftJoin('bank_accounts', 'withdrawals.bank_account_id', '=', 'bank_accounts.id')
            ->leftJoin('clients', 'withdrawals.client_id', '=', 'clients.id')
            ->where('withdrawals.tenant_id', $tenantId)
            ->where('withdrawals.payment_method', 'transfer')
            ->whereNull('withdrawals.deleted_at')
            ->select([
                'withdrawals.id',
                DB::raw("'withdrawal' as type"),
                'withdrawals.withdrawal_date as transaction_date',
                'bank_accounts.id as bank_account_id',
                'bank_accounts.bank_name',
                'bank_accounts.account_name',
                'withdrawals.description as note',
                'withdrawals.client_id as vendor_id',
                DB::raw('COALESCE(clients.name, withdrawals.client_name) as vendor_name'),
                'withdrawals.client_name as depositor_name',
                DB::raw('0 as deposit_amount'),
                'withdrawals.amount as withdrawal_amount',
                'withdrawals.account_code as transaction_type',
                DB::raw("CONCAT('withdrawal-', withdrawals.id) as source_id"),
                'withdrawals.created_at',
                'withdrawals.updated_at',
            ]);

        // 필터 적용: 날짜 범위
        if ($startDate) {
            $depositsQuery->whereDate('deposits.deposit_date', '>=', $startDate);
            $withdrawalsQuery->whereDate('withdrawals.withdrawal_date', '>=', $startDate);
        }
        if ($endDate) {
            $depositsQuery->whereDate('deposits.deposit_date', '<=', $endDate);
            $withdrawalsQuery->whereDate('withdrawals.withdrawal_date', '<=', $endDate);
        }

        // 필터 적용: 계좌
        if ($bankAccountId) {
            $depositsQuery->where('deposits.bank_account_id', $bankAccountId);
            $withdrawalsQuery->where('withdrawals.bank_account_id', $bankAccountId);
        }

        // 필터 적용: 입출금유형 (account_code)
        if ($transactionType) {
            if ($transactionType === 'unset') {
                $depositsQuery->whereNull('deposits.account_code');
                $withdrawalsQuery->whereNull('withdrawals.account_code');
            } else {
                $depositsQuery->where('deposits.account_code', $transactionType);
                $withdrawalsQuery->where('withdrawals.account_code', $transactionType);
            }
        }

        // 필터 적용: 검색어
        if ($search) {
            $depositsQuery->where(function ($q) use ($search) {
                $q->where('bank_accounts.bank_name', 'like', "%{$search}%")
                    ->orWhere('bank_accounts.account_name', 'like', "%{$search}%")
                    ->orWhere('deposits.client_name', 'like', "%{$search}%")
                    ->orWhere('clients.name', 'like', "%{$search}%")
                    ->orWhere('deposits.description', 'like', "%{$search}%");
            });

            $withdrawalsQuery->where(function ($q) use ($search) {
                $q->where('bank_accounts.bank_name', 'like', "%{$search}%")
                    ->orWhere('bank_accounts.account_name', 'like', "%{$search}%")
                    ->orWhere('withdrawals.client_name', 'like', "%{$search}%")
                    ->orWhere('clients.name', 'like', "%{$search}%")
                    ->orWhere('withdrawals.description', 'like', "%{$search}%");
            });
        }

        // UNION
        $unionQuery = $depositsQuery->union($withdrawalsQuery);

        // 정렬 컬럼 매핑
        $sortColumn = match ($sortBy) {
            'transaction_date' => 'transaction_date',
            'deposit_amount', 'withdrawal_amount', 'amount' => DB::raw('(deposit_amount + withdrawal_amount)'),
            default => 'transaction_date',
        };

        // 전체 조회하여 정렬 및 잔액 계산
        $allItems = DB::query()
            ->fromSub($unionQuery, 'transactions')
            ->orderBy($sortColumn, $sortDir)
            ->get();

        // 잔액 계산 (날짜순 정렬 기준)
        $balance = 0;
        $itemsWithBalance = $allItems->map(function ($item) use (&$balance) {
            $balance += $item->deposit_amount - $item->withdrawal_amount;
            $item->balance = $balance;

            return $item;
        });

        // 수동 페이지네이션
        $total = $itemsWithBalance->count();
        $offset = ($page - 1) * $perPage;
        $paginatedItems = $itemsWithBalance->slice($offset, $perPage)->values();

        return new LengthAwarePaginator(
            $paginatedItems,
            $total,
            $perPage,
            $page,
            ['path' => request()->url()]
        );
    }

    /**
     * 입출금 요약 통계
     */
    public function summary(array $params): array
    {
        $startDate = $params['start_date'] ?? null;
        $endDate = $params['end_date'] ?? null;
        $tenantId = $this->tenantId();

        // 입금 합계 (계좌이체)
        $depositQuery = Deposit::where('tenant_id', $tenantId)
            ->where('payment_method', 'transfer');
        if ($startDate) {
            $depositQuery->whereDate('deposit_date', '>=', $startDate);
        }
        if ($endDate) {
            $depositQuery->whereDate('deposit_date', '<=', $endDate);
        }
        $totalDeposit = $depositQuery->sum('amount');
        $depositUnsetCount = (clone $depositQuery)->whereNull('account_code')->count();

        // 출금 합계 (계좌이체)
        $withdrawalQuery = Withdrawal::where('tenant_id', $tenantId)
            ->where('payment_method', 'transfer');
        if ($startDate) {
            $withdrawalQuery->whereDate('withdrawal_date', '>=', $startDate);
        }
        if ($endDate) {
            $withdrawalQuery->whereDate('withdrawal_date', '<=', $endDate);
        }
        $totalWithdrawal = $withdrawalQuery->sum('amount');
        $withdrawalUnsetCount = (clone $withdrawalQuery)->whereNull('account_code')->count();

        return [
            'total_deposit' => (float) $totalDeposit,
            'total_withdrawal' => (float) $totalWithdrawal,
            'deposit_unset_count' => (int) $depositUnsetCount,
            'withdrawal_unset_count' => (int) $withdrawalUnsetCount,
        ];
    }

    /**
     * 계좌 목록 조회 (필터용)
     */
    public function getAccountOptions(): array
    {
        $tenantId = $this->tenantId();

        return BankAccount::where('tenant_id', $tenantId)
            ->where('status', 'active')
            ->orderBy('bank_name')
            ->orderBy('account_name')
            ->get()
            ->map(fn ($acc) => [
                'id' => $acc->id,
                'label' => "{$acc->bank_name}|{$acc->account_name}",
            ])
            ->toArray();
    }
}
