<?php

namespace App\Services;

use App\Models\Tenants\BankAccount;
use App\Models\Tenants\Bill;
use App\Models\Tenants\Deposit;
use App\Models\Tenants\ExpectedExpense;
use App\Models\Tenants\Purchase;
use App\Models\Tenants\Sale;
use App\Models\Tenants\Withdrawal;
use Carbon\Carbon;

/**
 * 일일 보고서 서비스
 */
class DailyReportService extends Service
{
    /**
     * 어음 및 외상매출채권 현황 조회
     */
    public function noteReceivables(array $params): array
    {
        $tenantId = $this->tenantId();
        $date = isset($params['date']) ? Carbon::parse($params['date']) : Carbon::today();

        // 수취어음 중 보관중 상태인 것만 조회 (만기일 기준)
        $bills = Bill::where('tenant_id', $tenantId)
            ->where('bill_type', 'received')
            ->where('status', 'stored')
            ->where('maturity_date', '>=', $date->copy()->startOfDay())
            ->orderBy('maturity_date', 'asc')
            ->get();

        return $bills->map(function ($bill) {
            return [
                'id' => (string) $bill->id,
                'content' => "(수취어음) {$bill->display_client_name} - {$bill->bill_number}",
                'current_balance' => (float) $bill->amount,
                'issue_date' => $bill->issue_date?->format('Y-m-d'),
                'due_date' => $bill->maturity_date?->format('Y-m-d'),
            ];
        })->values()->toArray();
    }

    /**
     * 일별 계좌 현황 조회
     */
    public function dailyAccounts(array $params): array
    {
        $tenantId = $this->tenantId();
        $date = isset($params['date']) ? Carbon::parse($params['date']) : Carbon::today();
        $startOfMonth = $date->copy()->startOfMonth();
        $endOfDay = $date->copy()->endOfDay();

        // 활성 계좌 목록
        $accounts = BankAccount::where('tenant_id', $tenantId)
            ->where('status', 'active')
            ->orderBy('is_primary', 'desc')
            ->orderBy('bank_name', 'asc')
            ->get();

        $result = [];

        foreach ($accounts as $account) {
            // 전월 이월: 이번 달 1일 이전까지의 누적 잔액
            $carryoverDeposits = Deposit::where('tenant_id', $tenantId)
                ->where('bank_account_id', $account->id)
                ->where('deposit_date', '<', $startOfMonth)
                ->sum('amount');

            $carryoverWithdrawals = Withdrawal::where('tenant_id', $tenantId)
                ->where('bank_account_id', $account->id)
                ->where('withdrawal_date', '<', $startOfMonth)
                ->sum('amount');

            $carryover = $carryoverDeposits - $carryoverWithdrawals;

            // 당일 수입 (입금)
            $income = Deposit::where('tenant_id', $tenantId)
                ->where('bank_account_id', $account->id)
                ->whereBetween('deposit_date', [$startOfMonth, $endOfDay])
                ->sum('amount');

            // 당일 지출 (출금)
            $expense = Withdrawal::where('tenant_id', $tenantId)
                ->where('bank_account_id', $account->id)
                ->whereBetween('withdrawal_date', [$startOfMonth, $endOfDay])
                ->sum('amount');

            // 잔액 = 전월이월 + 수입 - 지출
            $balance = $carryover + $income - $expense;

            // 매칭 상태: Deposit과 Withdrawal 금액이 일치하면 matched
            $matchStatus = abs($income - $expense) < 0.01 ? 'matched' : 'unmatched';

            $result[] = [
                'id' => (string) $account->id,
                'category' => "{$account->bank_name} {$account->getMaskedAccountNumber()}",
                'match_status' => $matchStatus,
                'carryover' => (float) $carryover,
                'income' => (float) $income,
                'expense' => (float) $expense,
                'balance' => (float) $balance,
                'currency' => 'KRW', // 현재는 KRW만 지원
            ];
        }

        return $result;
    }

    /**
     * 일일 보고서 요약 통계
     */
    public function summary(array $params): array
    {
        $tenantId = $this->tenantId();
        $date = isset($params['date']) ? Carbon::parse($params['date']) : Carbon::today();

        // 어음 합계
        $noteReceivableTotal = Bill::where('tenant_id', $tenantId)
            ->where('bill_type', 'received')
            ->where('status', 'stored')
            ->where('maturity_date', '>=', $date->copy()->startOfDay())
            ->sum('amount');

        // 계좌별 현황
        $dailyAccounts = $this->dailyAccounts($params);

        // 통화별 합계
        $krwTotal = collect($dailyAccounts)
            ->where('currency', 'KRW')
            ->reduce(function ($carry, $item) {
                return [
                    'carryover' => $carry['carryover'] + $item['carryover'],
                    'income' => $carry['income'] + $item['income'],
                    'expense' => $carry['expense'] + $item['expense'],
                    'balance' => $carry['balance'] + $item['balance'],
                ];
            }, ['carryover' => 0, 'income' => 0, 'expense' => 0, 'balance' => 0]);

        $usdTotal = collect($dailyAccounts)
            ->where('currency', 'USD')
            ->reduce(function ($carry, $item) {
                return [
                    'carryover' => $carry['carryover'] + $item['carryover'],
                    'income' => $carry['income'] + $item['income'],
                    'expense' => $carry['expense'] + $item['expense'],
                    'balance' => $carry['balance'] + $item['balance'],
                ];
            }, ['carryover' => 0, 'income' => 0, 'expense' => 0, 'balance' => 0]);

        // 운영자금 안정성 계산
        $cashAssetTotal = (float) $krwTotal['balance'];
        $monthlyOperatingExpense = $this->calculateMonthlyOperatingExpense($date);
        $operatingMonths = $monthlyOperatingExpense > 0
            ? round($cashAssetTotal / $monthlyOperatingExpense, 1)
            : null;
        $operatingStability = $this->getOperatingStability($operatingMonths);

        // 기획서 D1.7 자금현황 카드용 필드
        $receivableBalance = $this->calculateReceivableBalance($tenantId, $date);
        $payableBalance = $this->calculatePayableBalance($tenantId);
        $monthlyExpenseTotal = $this->calculateMonthlyExpenseTotal($tenantId, $date);

        return [
            'date' => $date->format('Y-m-d'),
            'day_of_week' => $date->locale('ko')->dayName,
            'note_receivable_total' => (float) $noteReceivableTotal,
            'foreign_currency_total' => (float) $usdTotal['balance'],
            'cash_asset_total' => $cashAssetTotal,
            'krw_totals' => $krwTotal,
            'usd_totals' => $usdTotal,
            // 운영자금 안정성 지표
            'monthly_operating_expense' => $monthlyOperatingExpense,
            'operating_months' => $operatingMonths,
            'operating_stability' => $operatingStability,
            // 자금현황 카드용
            'receivable_balance' => $receivableBalance,
            'payable_balance' => $payableBalance,
            'monthly_expense_total' => $monthlyExpenseTotal,
        ];
    }

    /**
     * 엑셀 내보내기용 데이터 조합
     * DailyReportExport가 기대하는 구조로 변환
     */
    public function exportData(array $params): array
    {
        $date = isset($params['date']) ? Carbon::parse($params['date']) : Carbon::today();
        $dateStr = $date->format('Y-m-d');

        // 화면과 동일한 계좌별 현황 데이터 재사용
        $dailyAccounts = $this->dailyAccounts($params);

        // KRW 계좌 합산 (화면 합계와 동일)
        $carryover = 0;
        $totalIncome = 0;
        $totalExpense = 0;
        $totalBalance = 0;

        $details = [];

        foreach ($dailyAccounts as $account) {
            $carryover += $account['carryover'];
            $totalIncome += $account['income'];
            $totalExpense += $account['expense'];
            $totalBalance += $account['balance'];

            // 계좌별 상세 내역
            if ($account['income'] > 0) {
                $details[] = [
                    'type_label' => '입금',
                    'client_name' => $account['category'],
                    'account_code' => '-',
                    'deposit_amount' => $account['income'],
                    'withdrawal_amount' => 0,
                    'description' => '',
                ];
            }

            if ($account['expense'] > 0) {
                $details[] = [
                    'type_label' => '출금',
                    'client_name' => $account['category'],
                    'account_code' => '-',
                    'deposit_amount' => 0,
                    'withdrawal_amount' => $account['expense'],
                    'description' => '',
                ];
            }
        }

        // 어음 및 외상매출채권 현황
        $noteReceivables = $this->noteReceivables($params);

        return [
            'date' => $dateStr,
            'previous_balance' => $carryover,
            'daily_deposit' => $totalIncome,
            'daily_withdrawal' => $totalExpense,
            'current_balance' => $totalBalance,
            'details' => $details,
            'note_receivables' => $noteReceivables,
        ];
    }

    /**
     * 미수금 잔액 계산
     * = 전체 매출 - 전체 입금 - 전체 수취어음 (기준일까지)
     * ReceivablesService.getTotalCarryForwardBalance() 동일 로직
     */
    private function calculateReceivableBalance(int $tenantId, Carbon $date): float
    {
        $endDate = $date->format('Y-m-d');

        $totalSales = Sale::where('tenant_id', $tenantId)
            ->whereNotNull('client_id')
            ->where('sale_date', '<=', $endDate)
            ->sum('total_amount');

        $totalDeposits = Deposit::where('tenant_id', $tenantId)
            ->whereNotNull('client_id')
            ->where('deposit_date', '<=', $endDate)
            ->sum('amount');

        $totalBills = Bill::where('tenant_id', $tenantId)
            ->whereNotNull('client_id')
            ->where('bill_type', 'received')
            ->where('issue_date', '<=', $endDate)
            ->sum('amount');

        return (float) ($totalSales - $totalDeposits - $totalBills);
    }

    /**
     * 미지급금 잔액 계산
     * = 미지급 상태(pending, partial, overdue)인 ExpectedExpense 합계
     */
    private function calculatePayableBalance(int $tenantId): float
    {
        return (float) ExpectedExpense::where('tenant_id', $tenantId)
            ->whereIn('payment_status', ['pending', 'partial', 'overdue'])
            ->sum('amount');
    }

    /**
     * 당월 예상 지출 합계 계산
     * = 당월 매입(Purchase) + 당월 예상지출(ExpectedExpense)
     */
    private function calculateMonthlyExpenseTotal(int $tenantId, Carbon $date): float
    {
        $startOfMonth = $date->copy()->startOfMonth()->format('Y-m-d');
        $endOfMonth = $date->copy()->endOfMonth()->format('Y-m-d');

        // 당월 매입 합계
        $purchaseTotal = Purchase::where('tenant_id', $tenantId)
            ->whereBetween('purchase_date', [$startOfMonth, $endOfMonth])
            ->sum('total_amount');

        // 당월 예상 지출 합계 (매입 외: 카드, 어음, 급여, 임대료 등)
        $expectedExpenseTotal = ExpectedExpense::where('tenant_id', $tenantId)
            ->whereBetween('expected_payment_date', [$startOfMonth, $endOfMonth])
            ->sum('amount');

        return (float) ($purchaseTotal + $expectedExpenseTotal);
    }

    /**
     * 직전 3개월 평균 월 운영비 계산
     *
     * @param  Carbon  $baseDate  기준일
     * @return float 월 평균 운영비
     */
    private function calculateMonthlyOperatingExpense(Carbon $baseDate): float
    {
        $tenantId = $this->tenantId();

        // 직전 3개월 범위: 기준일 전월 말일부터 3개월 전 1일까지
        $lastMonthEnd = $baseDate->copy()->subMonth()->endOfMonth();
        $threeMonthsAgo = $baseDate->copy()->subMonths(3)->startOfMonth();

        $totalExpense = Withdrawal::where('tenant_id', $tenantId)
            ->whereBetween('withdrawal_date', [$threeMonthsAgo, $lastMonthEnd])
            ->sum('amount');

        // 3개월 평균
        return round((float) $totalExpense / 3, 0);
    }

    /**
     * 운영자금 안정성 판정
     *
     * 색상 가이드 기준:
     * - warning (빨강): 3개월 미만 - 자금 부족 우려
     * - caution (주황): 3~6개월 - 자금 관리 필요
     * - stable (파랑): 6개월 이상 - 안정적
     *
     * @param  float|null  $months  운영 가능 개월 수
     * @return string 안정성 상태 (stable|caution|warning|unknown)
     */
    private function getOperatingStability(?float $months): string
    {
        if ($months === null) {
            return 'unknown';
        }

        if ($months >= 6) {
            return 'stable';    // 파랑 - 안정적
        }

        if ($months >= 3) {
            return 'caution';   // 주황 - 자금 관리 필요
        }

        return 'warning';       // 빨강 - 자금 부족 우려
    }
}
