<?php

namespace App\Services;

use App\Models\Orders\Client;
use App\Models\Tenants\Bill;
use App\Models\Tenants\Deposit;
use App\Models\Tenants\Sale;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

class VendorLedgerService extends Service
{
    /**
     * 거래처원장 목록 조회 (거래처별 매출/수금 집계)
     */
    public function index(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();
        $startDate = $params['start_date'] ?? null;
        $endDate = $params['end_date'] ?? null;
        $search = $params['search'] ?? null;
        $perPage = $params['per_page'] ?? 20;

        // 거래처 목록 조회
        $query = Client::query()
            ->where('tenant_id', $tenantId)
            ->where('is_active', true);

        // 거래처명 검색
        if (! empty($search)) {
            $query->where('name', 'like', "%{$search}%");
        }

        // 거래처 ID 목록
        $clientsQuery = clone $query;
        $clients = $clientsQuery->select('id', 'name', 'sales_payment_day')->get();

        // 매출 집계 서브쿼리
        $salesSubquery = Sale::query()
            ->select('client_id', DB::raw('SUM(total_amount) as total_sales'))
            ->where('tenant_id', $tenantId)
            ->when($startDate, fn ($q) => $q->where('sale_date', '>=', $startDate))
            ->when($endDate, fn ($q) => $q->where('sale_date', '<=', $endDate))
            ->groupBy('client_id');

        // 수금 집계 서브쿼리
        $depositsSubquery = Deposit::query()
            ->select('client_id', DB::raw('SUM(amount) as total_collection'))
            ->where('tenant_id', $tenantId)
            ->when($startDate, fn ($q) => $q->where('deposit_date', '>=', $startDate))
            ->when($endDate, fn ($q) => $q->where('deposit_date', '<=', $endDate))
            ->groupBy('client_id');

        // 이월잔액 서브쿼리 (기간 시작 전 매출 - 수금)
        $carryoverSalesSubquery = null;
        $carryoverDepositsSubquery = null;

        if ($startDate) {
            $carryoverSalesSubquery = Sale::query()
                ->select('client_id', DB::raw('COALESCE(SUM(total_amount), 0) as carryover_sales'))
                ->where('tenant_id', $tenantId)
                ->where('sale_date', '<', $startDate)
                ->groupBy('client_id');

            $carryoverDepositsSubquery = Deposit::query()
                ->select('client_id', DB::raw('COALESCE(SUM(amount), 0) as carryover_deposits'))
                ->where('tenant_id', $tenantId)
                ->where('deposit_date', '<', $startDate)
                ->groupBy('client_id');
        }

        // 메인 쿼리
        $mainQuery = Client::query()
            ->select([
                'clients.id',
                'clients.name',
                'clients.sales_payment_day',
                DB::raw('COALESCE(sales_agg.total_sales, 0) as period_sales'),
                DB::raw('COALESCE(deposits_agg.total_collection, 0) as period_collection'),
            ])
            ->where('clients.tenant_id', $tenantId)
            ->where('clients.is_active', true)
            ->leftJoinSub($salesSubquery, 'sales_agg', 'clients.id', '=', 'sales_agg.client_id')
            ->leftJoinSub($depositsSubquery, 'deposits_agg', 'clients.id', '=', 'deposits_agg.client_id');

        if ($carryoverSalesSubquery && $carryoverDepositsSubquery) {
            $mainQuery->addSelect([
                DB::raw('COALESCE(carryover_sales_agg.carryover_sales, 0) as carryover_sales'),
                DB::raw('COALESCE(carryover_deposits_agg.carryover_deposits, 0) as carryover_deposits'),
            ])
                ->leftJoinSub($carryoverSalesSubquery, 'carryover_sales_agg', 'clients.id', '=', 'carryover_sales_agg.client_id')
                ->leftJoinSub($carryoverDepositsSubquery, 'carryover_deposits_agg', 'clients.id', '=', 'carryover_deposits_agg.client_id');
        } else {
            $mainQuery->addSelect([
                DB::raw('0 as carryover_sales'),
                DB::raw('0 as carryover_deposits'),
            ]);
        }

        // 검색
        if (! empty($search)) {
            $mainQuery->where('clients.name', 'like', "%{$search}%");
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'name';
        $sortDir = $params['sort_dir'] ?? 'asc';
        $mainQuery->orderBy("clients.{$sortBy}", $sortDir);

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

    /**
     * 거래처원장 요약 통계
     */
    public function summary(array $params): array
    {
        $tenantId = $this->tenantId();
        $startDate = $params['start_date'] ?? null;
        $endDate = $params['end_date'] ?? null;

        // 기간 내 매출 합계
        $totalSales = Sale::query()
            ->where('tenant_id', $tenantId)
            ->when($startDate, fn ($q) => $q->where('sale_date', '>=', $startDate))
            ->when($endDate, fn ($q) => $q->where('sale_date', '<=', $endDate))
            ->sum('total_amount');

        // 기간 내 수금 합계
        $totalCollection = Deposit::query()
            ->where('tenant_id', $tenantId)
            ->when($startDate, fn ($q) => $q->where('deposit_date', '>=', $startDate))
            ->when($endDate, fn ($q) => $q->where('deposit_date', '<=', $endDate))
            ->sum('amount');

        // 이월잔액 (기간 시작 전 매출 - 수금)
        $carryoverBalance = 0;
        if ($startDate) {
            $carryoverSales = Sale::query()
                ->where('tenant_id', $tenantId)
                ->where('sale_date', '<', $startDate)
                ->sum('total_amount');

            $carryoverDeposits = Deposit::query()
                ->where('tenant_id', $tenantId)
                ->where('deposit_date', '<', $startDate)
                ->sum('amount');

            $carryoverBalance = (float) $carryoverSales - (float) $carryoverDeposits;
        }

        // 현재 잔액 = 이월잔액 + 매출 - 수금
        $balance = $carryoverBalance + (float) $totalSales - (float) $totalCollection;

        return [
            'carryover_balance' => $carryoverBalance,
            'total_sales' => (float) $totalSales,
            'total_collection' => (float) $totalCollection,
            'balance' => $balance,
        ];
    }

    /**
     * 거래처원장 상세 (거래처별 거래 내역)
     */
    public function show(int $clientId, array $params): array
    {
        $tenantId = $this->tenantId();
        $startDate = $params['start_date'] ?? null;
        $endDate = $params['end_date'] ?? null;

        // 거래처 정보
        $client = Client::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($clientId);

        // 이월잔액 계산
        $carryoverBalance = 0;
        if ($startDate) {
            $carryoverSales = Sale::query()
                ->where('tenant_id', $tenantId)
                ->where('client_id', $clientId)
                ->where('sale_date', '<', $startDate)
                ->sum('total_amount');

            $carryoverDeposits = Deposit::query()
                ->where('tenant_id', $tenantId)
                ->where('client_id', $clientId)
                ->where('deposit_date', '<', $startDate)
                ->sum('amount');

            $carryoverBalance = (float) $carryoverSales - (float) $carryoverDeposits;
        }

        // 거래 내역 조회 (매출 + 수금)
        $transactions = collect();

        // 매출 내역
        $sales = Sale::query()
            ->where('tenant_id', $tenantId)
            ->where('client_id', $clientId)
            ->when($startDate, fn ($q) => $q->where('sale_date', '>=', $startDate))
            ->when($endDate, fn ($q) => $q->where('sale_date', '<=', $endDate))
            ->orderBy('sale_date')
            ->get()
            ->map(fn ($sale) => [
                'id' => $sale->id,
                'date' => $sale->sale_date->format('Y-m-d'),
                'type' => 'sales',
                'description' => $sale->description ?? '매출',
                'sales_amount' => (float) $sale->total_amount,
                'collection_amount' => 0,
                'reference_id' => $sale->id,
                'reference_type' => 'sale',
                'has_action' => false,
                'is_highlighted' => ! $sale->tax_invoice_issued,
            ]);

        // 수금 내역
        $deposits = Deposit::query()
            ->where('tenant_id', $tenantId)
            ->where('client_id', $clientId)
            ->when($startDate, fn ($q) => $q->where('deposit_date', '>=', $startDate))
            ->when($endDate, fn ($q) => $q->where('deposit_date', '<=', $endDate))
            ->orderBy('deposit_date')
            ->get()
            ->map(fn ($deposit) => [
                'id' => $deposit->id,
                'date' => $deposit->deposit_date->format('Y-m-d'),
                'type' => 'collection',
                'description' => $deposit->description ?? '입금',
                'sales_amount' => 0,
                'collection_amount' => (float) $deposit->amount,
                'reference_id' => $deposit->id,
                'reference_type' => 'deposit',
                'has_action' => false,
                'is_highlighted' => false,
                'is_parenthesis' => $deposit->payment_method === 'check',
            ]);

        // 어음 내역
        $bills = Bill::query()
            ->where('tenant_id', $tenantId)
            ->where('client_id', $clientId)
            ->when($startDate, fn ($q) => $q->where('issue_date', '>=', $startDate))
            ->when($endDate, fn ($q) => $q->where('issue_date', '<=', $endDate))
            ->orderBy('issue_date')
            ->get()
            ->map(fn ($bill) => [
                'id' => $bill->id,
                'date' => $bill->issue_date,
                'type' => 'note',
                'description' => "수취 어음 (만기 {$bill->maturity_date})",
                'sales_amount' => 0,
                'collection_amount' => (float) $bill->amount,
                'reference_id' => $bill->id,
                'reference_type' => 'bill',
                'has_action' => true,
                'is_highlighted' => false,
                'is_parenthesis' => true,
                'note_info' => $bill->maturity_date,
            ]);

        // 전체 거래 내역 합치기 및 정렬
        $allTransactions = $sales->merge($deposits)->merge($bills)
            ->sortBy('date')
            ->values();

        // 잔액 계산
        $runningBalance = $carryoverBalance;
        $transactions = $allTransactions->map(function ($item) use (&$runningBalance) {
            $runningBalance = $runningBalance + $item['sales_amount'] - $item['collection_amount'];
            $item['balance'] = $runningBalance;

            return $item;
        });

        // 합계 계산
        $totalSales = $transactions->sum('sales_amount');
        $totalCollection = $transactions->sum('collection_amount');

        return [
            'client' => [
                'id' => $client->id,
                'name' => $client->name,
                'business_number' => $client->business_no,
                'representative_name' => $client->contact_person,
                'phone' => $client->phone,
                'mobile' => $client->mobile,
                'fax' => $client->fax,
                'email' => $client->email,
                'address' => $client->address,
            ],
            'period' => [
                'start_date' => $startDate,
                'end_date' => $endDate,
            ],
            'carryover_balance' => $carryoverBalance,
            'total_sales' => $totalSales,
            'total_collection' => $totalCollection,
            'balance' => $runningBalance,
            'transactions' => $transactions->toArray(),
        ];
    }
}
