<?php

namespace App\Http\Controllers\Finance;

use App\Http\Controllers\Controller;
use App\Models\Barobill\HometaxInvoice;
use App\Models\Barobill\HometaxInvoiceJournal;
use App\Models\Finance\JournalEntryLine;
use App\Models\Finance\Receivable;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class ReceivableController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);

        $query = Receivable::forTenant($tenantId);

        if ($search = $request->input('search')) {
            $query->where(function ($q) use ($search) {
                $q->where('customer_name', 'like', "%{$search}%")
                    ->orWhere('invoice_no', 'like', "%{$search}%");
            });
        }

        if ($status = $request->input('status')) {
            if ($status !== 'all') {
                $query->where('status', $status);
            }
        }

        if ($category = $request->input('category')) {
            if ($category !== 'all') {
                $query->where('category', $category);
            }
        }

        $receivables = $query->orderBy('created_at', 'desc')
            ->get()
            ->map(function ($item) {
                return [
                    'id' => $item->id,
                    'customerName' => $item->customer_name,
                    'invoiceNo' => $item->invoice_no,
                    'issueDate' => $item->issue_date?->format('Y-m-d'),
                    'dueDate' => $item->due_date?->format('Y-m-d'),
                    'category' => $item->category,
                    'amount' => $item->amount,
                    'collectedAmount' => $item->collected_amount,
                    'status' => $item->status,
                    'description' => $item->description,
                    'memo' => $item->memo,
                ];
            });

        $allQuery = Receivable::forTenant($tenantId);
        $all = (clone $allQuery)->get();

        $totalAmount = $all->sum('amount');
        $totalCollected = $all->sum('collected_amount');
        $overdueAmount = $all->where('status', 'overdue')->sum(function ($item) {
            return $item->amount - $item->collected_amount;
        });

        $stats = [
            'totalAmount' => $totalAmount,
            'totalCollected' => $totalCollected,
            'totalOutstanding' => $totalAmount - $totalCollected,
            'overdueAmount' => $overdueAmount,
            'count' => $all->count(),
        ];

        return response()->json([
            'success' => true,
            'data' => $receivables,
            'stats' => $stats,
        ]);
    }

    public function store(Request $request): JsonResponse
    {
        $request->validate([
            'customerName' => 'required|string|max:100',
            'invoiceNo' => 'required|string|max:50',
            'amount' => 'required|integer|min:0',
        ]);

        $tenantId = session('selected_tenant_id', 1);

        $receivable = Receivable::create([
            'tenant_id' => $tenantId,
            'customer_name' => $request->input('customerName'),
            'invoice_no' => $request->input('invoiceNo'),
            'issue_date' => $request->input('issueDate'),
            'due_date' => $request->input('dueDate'),
            'category' => $request->input('category', '서비스'),
            'amount' => $request->input('amount', 0),
            'collected_amount' => 0,
            'status' => 'outstanding',
            'description' => $request->input('description'),
            'memo' => $request->input('memo'),
        ]);

        return response()->json([
            'success' => true,
            'message' => '미수금이 등록되었습니다.',
        ]);
    }

    public function update(Request $request, int $id): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        $receivable = Receivable::forTenant($tenantId)->findOrFail($id);

        $request->validate([
            'customerName' => 'required|string|max:100',
            'invoiceNo' => 'required|string|max:50',
            'amount' => 'required|integer|min:0',
        ]);

        $receivable->update([
            'customer_name' => $request->input('customerName'),
            'invoice_no' => $request->input('invoiceNo'),
            'issue_date' => $request->input('issueDate'),
            'due_date' => $request->input('dueDate'),
            'category' => $request->input('category'),
            'amount' => $request->input('amount'),
            'status' => $request->input('status', $receivable->status),
            'description' => $request->input('description'),
            'memo' => $request->input('memo'),
        ]);

        return response()->json([
            'success' => true,
            'message' => '미수금이 수정되었습니다.',
        ]);
    }

    public function collect(Request $request, int $id): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        $receivable = Receivable::forTenant($tenantId)->findOrFail($id);

        $request->validate([
            'collectAmount' => 'required|integer|min:1',
        ]);

        $collectAmount = $request->input('collectAmount');
        $remaining = $receivable->amount - $receivable->collected_amount;

        if ($collectAmount > $remaining) {
            return response()->json([
                'success' => false,
                'message' => '수금액이 잔액을 초과합니다.',
            ], 422);
        }

        $newCollected = $receivable->collected_amount + $collectAmount;
        $newStatus = $newCollected >= $receivable->amount ? 'collected' : 'partial';

        $receivable->update([
            'collected_amount' => $newCollected,
            'status' => $newStatus,
        ]);

        return response()->json([
            'success' => true,
            'message' => '수금 처리되었습니다.',
        ]);
    }

    public function destroy(int $id): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        $receivable = Receivable::forTenant($tenantId)->findOrFail($id);
        $receivable->delete();

        return response()->json([
            'success' => true,
            'message' => '미수금이 삭제되었습니다.',
        ]);
    }

    /**
     * 외상매출금 원장 (홈택스 분개 + 일반전표에서 계정코드 108 집계)
     */
    public function ledger(Request $request): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        $startDate = $request->input('startDate');
        $endDate = $request->input('endDate');
        $partner = $request->input('partner');
        $source = $request->input('source', 'all');

        // 분개 완료된 매출세금계산서 ID
        $journaledInvoiceIds = [];
        if ($source !== 'journal') {
            $journaledInvoiceIds = HometaxInvoiceJournal::where('tenant_id', $tenantId)
                ->where('invoice_type', 'sales')
                ->distinct()
                ->pluck('hometax_invoice_id')
                ->toArray();
        }

        // 이월 잔액 계산 (startDate 이전)
        $priorBalance = 0;
        if ($startDate) {
            if ($source !== 'journal') {
                $priorHtQuery = HometaxInvoiceJournal::where('tenant_id', $tenantId)
                    ->where('account_code', '108')
                    ->where('invoice_type', 'sales')
                    ->where('write_date', '<', $startDate);
                if ($partner) {
                    $priorHtQuery->where('trading_partner_name', 'like', "%{$partner}%");
                }
                $priorHtData = $priorHtQuery->selectRaw('SUM(debit_amount) as td, SUM(credit_amount) as tc')->first();
                $priorBalance += ($priorHtData->td ?? 0) - ($priorHtData->tc ?? 0);

                $priorUnjQuery = HometaxInvoice::where('tenant_id', $tenantId)
                    ->where('invoice_type', 'sales')
                    ->whereNotIn('id', $journaledInvoiceIds)
                    ->where('write_date', '<', $startDate);
                if ($partner) {
                    $priorUnjQuery->where('invoicee_corp_name', 'like', "%{$partner}%");
                }
                $priorBalance += (int) $priorUnjQuery->sum('total_amount');
            }
            if ($source !== 'hometax') {
                $priorJnlQuery = JournalEntryLine::where('journal_entry_lines.tenant_id', $tenantId)
                    ->where('journal_entry_lines.account_code', '108')
                    ->join('journal_entries', 'journal_entries.id', '=', 'journal_entry_lines.journal_entry_id')
                    ->whereNull('journal_entries.deleted_at')
                    ->where('journal_entries.entry_date', '<', $startDate);
                if ($partner) {
                    $priorJnlQuery->where('journal_entry_lines.trading_partner_name', 'like', "%{$partner}%");
                }
                $priorJnlData = $priorJnlQuery->selectRaw('SUM(journal_entry_lines.debit_amount) as td, SUM(journal_entry_lines.credit_amount) as tc')->first();
                $priorBalance += ($priorJnlData->td ?? 0) - ($priorJnlData->tc ?? 0);
            }
        }

        $items = collect();

        // 1) 홈택스 매출세금계산서에서 외상매출금 조회
        if ($source !== 'journal') {
            // 1-a) 분개 완료된 건: hometax_invoice_journals에서 계정코드 108
            $hometaxQuery = HometaxInvoiceJournal::where('tenant_id', $tenantId)
                ->where('account_code', '108')
                ->where('invoice_type', 'sales');

            if ($startDate) {
                $hometaxQuery->where('write_date', '>=', $startDate);
            }
            if ($endDate) {
                $hometaxQuery->where('write_date', '<=', $endDate);
            }
            if ($partner) {
                $hometaxQuery->where('trading_partner_name', 'like', "%{$partner}%");
            }

            $hometaxItems = $hometaxQuery->get()->map(fn ($j) => [
                'date' => $j->write_date?->format('Y-m-d'),
                'source' => 'hometax',
                'sourceLabel' => '홈택스 매출',
                'refNo' => $j->nts_confirm_num,
                'tradingPartnerName' => $j->trading_partner_name,
                'description' => $j->description ?: '매출세금계산서',
                'debitAmount' => $j->dc_type === 'debit' ? (int) $j->debit_amount : 0,
                'creditAmount' => $j->dc_type === 'credit' ? (int) $j->credit_amount : 0,
            ]);

            $items = $items->merge($hometaxItems);

            // 1-b) 미분개 매출세금계산서: total_amount를 차변(발생)으로 표시
            $unjournaledQuery = HometaxInvoice::where('tenant_id', $tenantId)
                ->where('invoice_type', 'sales')
                ->whereNotIn('id', $journaledInvoiceIds);

            if ($startDate) {
                $unjournaledQuery->where('write_date', '>=', $startDate);
            }
            if ($endDate) {
                $unjournaledQuery->where('write_date', '<=', $endDate);
            }
            if ($partner) {
                $unjournaledQuery->where('invoicee_corp_name', 'like', "%{$partner}%");
            }

            $unjournaledItems = $unjournaledQuery->get()->map(fn ($inv) => [
                'date' => $inv->write_date?->format('Y-m-d'),
                'source' => 'hometax',
                'sourceLabel' => '홈택스 매출 (미분개)',
                'refNo' => $inv->nts_confirm_num,
                'tradingPartnerName' => $inv->invoicee_corp_name,
                'description' => '매출세금계산서 (미분개)',
                'debitAmount' => (int) $inv->total_amount,
                'creditAmount' => 0,
            ]);

            $items = $items->merge($unjournaledItems);
        }

        // 2) 일반전표에서 외상매출금(108) 조회
        if ($source !== 'hometax') {
            $journalQuery = JournalEntryLine::where('journal_entry_lines.tenant_id', $tenantId)
                ->where('journal_entry_lines.account_code', '108')
                ->join('journal_entries', 'journal_entries.id', '=', 'journal_entry_lines.journal_entry_id')
                ->whereNull('journal_entries.deleted_at')
                ->select('journal_entry_lines.*', 'journal_entries.entry_date', 'journal_entries.entry_no');

            if ($startDate) {
                $journalQuery->where('journal_entries.entry_date', '>=', $startDate);
            }
            if ($endDate) {
                $journalQuery->where('journal_entries.entry_date', '<=', $endDate);
            }
            if ($partner) {
                $journalQuery->where('journal_entry_lines.trading_partner_name', 'like', "%{$partner}%");
            }

            $journalItems = $journalQuery->get()->map(fn ($l) => [
                'date' => $l->entry_date instanceof \Carbon\Carbon ? $l->entry_date->format('Y-m-d') : $l->entry_date,
                'source' => 'journal',
                'sourceLabel' => '일반전표 '.$l->entry_no,
                'refNo' => $l->entry_no,
                'tradingPartnerName' => $l->trading_partner_name,
                'description' => $l->description ?: '일반전표',
                'debitAmount' => (int) $l->debit_amount,
                'creditAmount' => (int) $l->credit_amount,
            ]);

            $items = $items->merge($journalItems);
        }

        // 날짜순 정렬 + 누적잔액 계산 (이월잔액부터 시작)
        $sorted = $items->sortBy('date')->values();
        $balance = $priorBalance;
        $sorted = $sorted->map(function ($item) use (&$balance) {
            $balance += $item['debitAmount'] - $item['creditAmount'];
            $item['balance'] = $balance;

            return $item;
        });

        $totalDebit = $sorted->sum('debitAmount');
        $totalCredit = $sorted->sum('creditAmount');
        $partnerCount = $sorted->pluck('tradingPartnerName')->filter()->unique()->count();

        return response()->json([
            'success' => true,
            'data' => $sorted->values(),
            'stats' => [
                'priorBalance' => $priorBalance,
                'totalDebit' => $totalDebit,
                'totalCredit' => $totalCredit,
                'balance' => $priorBalance + $totalDebit - $totalCredit,
                'partnerCount' => $partnerCount,
            ],
        ]);
    }

    /**
     * 거래처별 외상매출금 요약 (이월잔액 포함)
     */
    public function summary(Request $request): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        $startDate = $request->input('startDate');
        $endDate = $request->input('endDate');

        // 분개 완료된 매출세금계산서 ID (전 기간)
        $journaledInvoiceIds = HometaxInvoiceJournal::where('tenant_id', $tenantId)
            ->where('invoice_type', 'sales')
            ->distinct()
            ->pluck('hometax_invoice_id')
            ->toArray();

        // 0. 이월 잔액 계산 (startDate 이전의 누적 잔액)
        $priorBalanceMap = [];

        if ($startDate) {
            // 이월 - 홈택스 분개 완료건 (account 108, sales)
            HometaxInvoiceJournal::where('tenant_id', $tenantId)
                ->where('account_code', '108')
                ->where('invoice_type', 'sales')
                ->where('write_date', '<', $startDate)
                ->select(
                    'trading_partner_name',
                    DB::raw('SUM(debit_amount) as total_debit'),
                    DB::raw('SUM(credit_amount) as total_credit')
                )
                ->groupBy('trading_partner_name')
                ->get()
                ->each(function ($row) use (&$priorBalanceMap) {
                    $key = $row->trading_partner_name;
                    if (! isset($priorBalanceMap[$key])) {
                        $priorBalanceMap[$key] = ['debit' => 0, 'credit' => 0];
                    }
                    $priorBalanceMap[$key]['debit'] += $row->total_debit;
                    $priorBalanceMap[$key]['credit'] += $row->total_credit;
                });

            // 이월 - 미분개 매출세금계산서 (차변 발생)
            HometaxInvoice::where('tenant_id', $tenantId)
                ->where('invoice_type', 'sales')
                ->whereNotIn('id', $journaledInvoiceIds)
                ->where('write_date', '<', $startDate)
                ->select('invoicee_corp_name', DB::raw('SUM(total_amount) as total_amount'))
                ->groupBy('invoicee_corp_name')
                ->get()
                ->each(function ($row) use (&$priorBalanceMap) {
                    $key = $row->invoicee_corp_name;
                    if (! isset($priorBalanceMap[$key])) {
                        $priorBalanceMap[$key] = ['debit' => 0, 'credit' => 0];
                    }
                    $priorBalanceMap[$key]['debit'] += $row->total_amount;
                });

            // 이월 - 일반전표 (account 108)
            JournalEntryLine::where('journal_entry_lines.tenant_id', $tenantId)
                ->where('journal_entry_lines.account_code', '108')
                ->join('journal_entries', function ($join) {
                    $join->on('journal_entries.id', '=', 'journal_entry_lines.journal_entry_id')
                        ->whereNull('journal_entries.deleted_at');
                })
                ->where('journal_entries.entry_date', '<', $startDate)
                ->select(
                    'journal_entry_lines.trading_partner_name',
                    DB::raw('SUM(journal_entry_lines.debit_amount) as total_debit'),
                    DB::raw('SUM(journal_entry_lines.credit_amount) as total_credit')
                )
                ->groupBy('journal_entry_lines.trading_partner_name')
                ->get()
                ->each(function ($row) use (&$priorBalanceMap) {
                    $key = $row->trading_partner_name;
                    if (! isset($priorBalanceMap[$key])) {
                        $priorBalanceMap[$key] = ['debit' => 0, 'credit' => 0];
                    }
                    $priorBalanceMap[$key]['debit'] += $row->total_debit;
                    $priorBalanceMap[$key]['credit'] += $row->total_credit;
                });
        }

        $items = collect();

        // 1) 홈택스 매출세금계산서에서 외상매출금
        // 1-a) 분개 완료된 건
        $hometaxQuery = HometaxInvoiceJournal::where('tenant_id', $tenantId)
            ->where('account_code', '108')
            ->where('invoice_type', 'sales');

        if ($startDate) {
            $hometaxQuery->where('write_date', '>=', $startDate);
        }
        if ($endDate) {
            $hometaxQuery->where('write_date', '<=', $endDate);
        }

        $hometaxItems = $hometaxQuery->get()->map(fn ($j) => [
            'tradingPartnerName' => $j->trading_partner_name,
            'debitAmount' => $j->dc_type === 'debit' ? (int) $j->debit_amount : 0,
            'creditAmount' => $j->dc_type === 'credit' ? (int) $j->credit_amount : 0,
            'date' => $j->write_date?->format('Y-m-d'),
        ]);
        $items = $items->merge($hometaxItems);

        // 1-b) 미분개 매출세금계산서
        $unjournaledQuery = HometaxInvoice::where('tenant_id', $tenantId)
            ->where('invoice_type', 'sales')
            ->whereNotIn('id', $journaledInvoiceIds);

        if ($startDate) {
            $unjournaledQuery->where('write_date', '>=', $startDate);
        }
        if ($endDate) {
            $unjournaledQuery->where('write_date', '<=', $endDate);
        }

        $unjournaledItems = $unjournaledQuery->get()->map(fn ($inv) => [
            'tradingPartnerName' => $inv->invoicee_corp_name,
            'debitAmount' => (int) $inv->total_amount,
            'creditAmount' => 0,
            'date' => $inv->write_date?->format('Y-m-d'),
        ]);
        $items = $items->merge($unjournaledItems);

        // 2) 일반전표에서 외상매출금(108)
        $journalQuery = JournalEntryLine::where('journal_entry_lines.tenant_id', $tenantId)
            ->where('journal_entry_lines.account_code', '108')
            ->join('journal_entries', 'journal_entries.id', '=', 'journal_entry_lines.journal_entry_id')
            ->whereNull('journal_entries.deleted_at')
            ->select('journal_entry_lines.*', 'journal_entries.entry_date');

        if ($startDate) {
            $journalQuery->where('journal_entries.entry_date', '>=', $startDate);
        }
        if ($endDate) {
            $journalQuery->where('journal_entries.entry_date', '<=', $endDate);
        }

        $journalItems = $journalQuery->get()->map(fn ($l) => [
            'tradingPartnerName' => $l->trading_partner_name,
            'debitAmount' => (int) $l->debit_amount,
            'creditAmount' => (int) $l->credit_amount,
            'date' => $l->entry_date instanceof \Carbon\Carbon ? $l->entry_date->format('Y-m-d') : $l->entry_date,
        ]);
        $items = $items->merge($journalItems);

        // 거래처별 그룹핑 (이월 잔액 포함)
        $grouped = $items->groupBy('tradingPartnerName')->map(function ($group, $partnerName) use ($priorBalanceMap) {
            $totalDebit = $group->sum('debitAmount');
            $totalCredit = $group->sum('creditAmount');
            $prior = $priorBalanceMap[$partnerName] ?? null;
            $priorBalance = $prior ? ($prior['debit'] - $prior['credit']) : 0;

            return [
                'tradingPartnerName' => $partnerName ?: '(미지정)',
                'priorBalance' => $priorBalance,
                'totalDebit' => $totalDebit,
                'totalCredit' => $totalCredit,
                'balance' => $priorBalance + $totalDebit - $totalCredit,
                'lastTransactionDate' => $group->pluck('date')->filter()->sort()->last(),
                'transactionCount' => $group->count(),
            ];
        });

        // 이월 잔액만 있고 당기 거래가 없는 거래처도 포함
        $existingPartners = $grouped->keys()->toArray();
        foreach ($priorBalanceMap as $partnerName => $prior) {
            $priorBalance = $prior['debit'] - $prior['credit'];
            if ($priorBalance != 0 && ! in_array($partnerName, $existingPartners)) {
                $grouped[$partnerName] = [
                    'tradingPartnerName' => $partnerName ?: '(미지정)',
                    'priorBalance' => $priorBalance,
                    'totalDebit' => 0,
                    'totalCredit' => 0,
                    'balance' => $priorBalance,
                    'lastTransactionDate' => null,
                    'transactionCount' => 0,
                ];
            }
        }

        $grouped = $grouped->sortByDesc('balance')->values();

        return response()->json([
            'success' => true,
            'data' => $grouped,
        ]);
    }
}
