<?php

namespace App\Services;

use App\Models\Barobill\BankTransaction as BarobillBankTransaction;
use App\Models\Finance\BankAccount;
use App\Models\Finance\BankTransaction;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class BankAccountService
{
    // =========================================================================
    // 계좌 목록 조회
    // =========================================================================

    /**
     * 계좌 목록 조회 (페이지네이션)
     */
    public function getAccounts(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = BankAccount::query();

        // Soft Delete 필터
        if (isset($filters['trashed'])) {
            if ($filters['trashed'] === 'only') {
                $query->onlyTrashed();
            } elseif ($filters['trashed'] === 'with') {
                $query->withTrashed();
            }
        }

        // 검색 필터
        if (! empty($filters['search'])) {
            $search = $filters['search'];
            $query->where(function ($q) use ($search) {
                $q->where('bank_name', 'like', "%{$search}%")
                    ->orWhere('account_number', 'like', "%{$search}%")
                    ->orWhere('account_holder', 'like', "%{$search}%");
            });
        }

        // 은행 필터
        if (! empty($filters['bank_name'])) {
            $query->where('bank_name', $filters['bank_name']);
        }

        // 예금종류 필터
        if (! empty($filters['account_type'])) {
            $query->where('account_type', $filters['account_type']);
        }

        // 활성 상태 필터 (status 기반)
        if (isset($filters['status'])) {
            $query->where('status', $filters['status']);
        }

        return $query
            ->addSelect(['*'])
            ->addSelect([
                'latest_barobill_trans_date' => BarobillBankTransaction::select('trans_date')
                    ->whereColumn('bank_account_num', DB::raw("REPLACE(bank_accounts.account_number, '-', '')"))
                    ->orderByDesc('trans_date')
                    ->orderByDesc('trans_time')
                    ->limit(1),
                'latest_barobill_trans_time' => BarobillBankTransaction::select('trans_time')
                    ->whereColumn('bank_account_num', DB::raw("REPLACE(bank_accounts.account_number, '-', '')"))
                    ->orderByDesc('trans_date')
                    ->orderByDesc('trans_time')
                    ->limit(1),
            ])
            ->orderBy('sort_order')
            ->orderBy('bank_name')
            ->paginate($perPage);
    }

    /**
     * 모든 계좌 목록 (드롭다운용)
     */
    public function getAllAccounts(): Collection
    {
        return BankAccount::active()
            ->ordered()
            ->get(['id', 'bank_name', 'account_number', 'account_type', 'balance']);
    }

    /**
     * 은행별 통계
     */
    public function getStatsByBank(): Collection
    {
        return BankAccount::active()
            ->select('bank_name')
            ->selectRaw('COUNT(*) as count')
            ->selectRaw('SUM(balance) as total_balance')
            ->groupBy('bank_name')
            ->orderBy('total_balance', 'desc')
            ->get();
    }

    // =========================================================================
    // 계좌 CRUD
    // =========================================================================

    /**
     * 계좌 상세 조회
     */
    public function getAccountById(int $id, bool $withTrashed = false): ?BankAccount
    {
        $query = BankAccount::query();

        if ($withTrashed) {
            $query->withTrashed();
        }

        return $query->find($id);
    }

    /**
     * 계좌 생성
     */
    public function createAccount(array $data): BankAccount
    {
        $data['created_by'] = auth()->id();
        $data['tenant_id'] = $data['tenant_id'] ?? session('selected_tenant_id') ?? auth()->user()?->tenant_id;

        return BankAccount::create($data);
    }

    /**
     * 계좌 수정
     */
    public function updateAccount(BankAccount $account, array $data): BankAccount
    {
        $data['updated_by'] = auth()->id();

        $account->update($data);

        return $account->fresh();
    }

    /**
     * 계좌 삭제 (Soft Delete)
     */
    public function deleteAccount(BankAccount $account): bool
    {
        $account->deleted_by = auth()->id();
        $account->save();

        return $account->delete();
    }

    /**
     * 계좌 복원
     */
    public function restoreAccount(BankAccount $account): bool
    {
        $account->deleted_by = null;

        return $account->restore();
    }

    /**
     * 계좌 영구 삭제
     */
    public function forceDeleteAccount(BankAccount $account): bool
    {
        return $account->forceDelete();
    }

    // =========================================================================
    // 계좌 상태 토글
    // =========================================================================

    /**
     * 활성/비활성 토글 (status 기반)
     */
    public function toggleActive(BankAccount $account): BankAccount
    {
        $newStatus = $account->status === 'active' ? 'inactive' : 'active';

        $account->update([
            'status' => $newStatus,
            'updated_by' => auth()->id(),
        ]);

        return $account->fresh();
    }

    // =========================================================================
    // 거래내역 관련
    // =========================================================================

    /**
     * 계좌의 거래내역 조회
     */
    public function getTransactions(int $accountId, array $filters = [], int $perPage = 20): LengthAwarePaginator
    {
        $query = BankTransaction::forAccount($accountId);

        // Soft Delete 필터
        if (isset($filters['trashed'])) {
            if ($filters['trashed'] === 'only') {
                $query->onlyTrashed();
            } elseif ($filters['trashed'] === 'with') {
                $query->withTrashed();
            }
        }

        // 검색 필터
        if (! empty($filters['search'])) {
            $search = $filters['search'];
            $query->where(function ($q) use ($search) {
                $q->where('description', 'like', "%{$search}%")
                    ->orWhere('counterparty', 'like', "%{$search}%")
                    ->orWhere('reference_number', 'like', "%{$search}%");
            });
        }

        // 거래유형 필터
        if (! empty($filters['transaction_type'])) {
            $query->ofType($filters['transaction_type']);
        }

        // 날짜 범위 필터
        if (! empty($filters['start_date']) && ! empty($filters['end_date'])) {
            $query->dateBetween($filters['start_date'], $filters['end_date']);
        } elseif (! empty($filters['start_date'])) {
            $query->where('transaction_date', '>=', $filters['start_date']);
        } elseif (! empty($filters['end_date'])) {
            $query->where('transaction_date', '<=', $filters['end_date']);
        }

        // 대사 상태 필터
        if (isset($filters['is_reconciled'])) {
            $query->reconciled((bool) $filters['is_reconciled']);
        }

        return $query
            ->with('bankAccount:id,bank_name,account_number')
            ->latest()
            ->paginate($perPage);
    }

    /**
     * 거래내역 생성
     */
    public function createTransaction(array $data): BankTransaction
    {
        return DB::transaction(function () use ($data) {
            $account = BankAccount::findOrFail($data['bank_account_id']);

            // 거래 후 잔액 계산
            $newBalance = match ($data['transaction_type']) {
                BankTransaction::TYPE_DEPOSIT => $account->balance + $data['amount'],
                BankTransaction::TYPE_WITHDRAWAL, BankTransaction::TYPE_TRANSFER => $account->balance - $data['amount'],
                default => $account->balance,
            };

            $data['balance_after'] = $newBalance;
            $data['tenant_id'] = $account->tenant_id;
            $data['created_by'] = auth()->id();

            $transaction = BankTransaction::create($data);

            // 계좌 잔액 업데이트
            $account->updateBalance($newBalance);

            return $transaction;
        });
    }

    /**
     * 거래내역 수정
     */
    public function updateTransaction(BankTransaction $transaction, array $data): BankTransaction
    {
        $data['updated_by'] = auth()->id();

        $transaction->update($data);

        return $transaction->fresh();
    }

    /**
     * 거래내역 삭제
     */
    public function deleteTransaction(BankTransaction $transaction): bool
    {
        $transaction->deleted_by = auth()->id();
        $transaction->save();

        return $transaction->delete();
    }

    // =========================================================================
    // 일괄 작업
    // =========================================================================

    /**
     * 일괄 삭제
     */
    public function bulkDelete(array $ids): int
    {
        return BankAccount::whereIn('id', $ids)
            ->update([
                'deleted_by' => auth()->id(),
                'deleted_at' => now(),
            ]);
    }

    /**
     * 일괄 복원
     */
    public function bulkRestore(array $ids): int
    {
        return BankAccount::onlyTrashed()
            ->whereIn('id', $ids)
            ->update([
                'deleted_by' => null,
                'deleted_at' => null,
            ]);
    }

    /**
     * 일괄 영구 삭제
     */
    public function bulkForceDelete(array $ids): int
    {
        return BankAccount::onlyTrashed()
            ->whereIn('id', $ids)
            ->forceDelete();
    }

    // =========================================================================
    // 요약 및 통계
    // =========================================================================

    /**
     * 전체 요약 통계
     */
    public function getSummary(): array
    {
        $accounts = BankAccount::active()->get();

        return [
            'total_accounts' => $accounts->count(),
            'total_balance' => $accounts->sum('balance'),
            'formatted_total_balance' => number_format($accounts->sum('balance')).'원',
            'by_bank' => $accounts->groupBy('bank_name')->map(fn ($group) => [
                'count' => $group->count(),
                'total' => $group->sum('balance'),
            ]),
        ];
    }
}
