<?php

namespace App\Services;

use App\Models\BadDebts\BadDebt;
use App\Models\Orders\Client;
use App\Models\Orders\Order;
use App\Models\Tenants\Approval;
use App\Models\Tenants\ApprovalStep;
use App\Models\Tenants\ExpectedExpense;
use App\Models\Tenants\Leave;
use App\Models\Tenants\Stock;
use Carbon\Carbon;

/**
 * CEO 대시보드 오늘의 이슈 리스트 서비스
 *
 * 각 카테고리별 상세 알림 항목을 집계하여 리스트 형태로 제공
 */
class TodayIssueService extends Service
{
    /**
     * 오늘의 이슈 리스트 조회
     *
     * @param  int  $limit  조회할 최대 항목 수 (기본 30)
     */
    public function summary(int $limit = 30): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();
        $today = Carbon::today();

        // 각 카테고리별 이슈 수집
        $issues = collect();

        // 1. 수주 성공 (최근 7일)
        $issues = $issues->merge($this->getOrderSuccessIssues($tenantId, $today));

        // 2. 미수금 이슈 (주식 이슈 - 연체 미수금)
        $issues = $issues->merge($this->getReceivableIssues($tenantId));

        // 3. 재고 이슈 (직정 제고 - 안전재고 미달)
        $issues = $issues->merge($this->getStockIssues($tenantId));

        // 4. 지출예상내역서 (승인 대기 건)
        $issues = $issues->merge($this->getExpectedExpenseIssues($tenantId));

        // 5. 세금 신고 (부가세 D-day)
        $issues = $issues->merge($this->getTaxIssues($tenantId, $today));

        // 6. 결재 요청 (내 결재 대기 건)
        $issues = $issues->merge($this->getApprovalIssues($tenantId, $userId));

        // 7. 기타 (신규 거래처 등록)
        $issues = $issues->merge($this->getOtherIssues($tenantId, $today));

        // 날짜 기준 내림차순 정렬 후 limit 적용
        $sortedIssues = $issues
            ->sortByDesc('created_at')
            ->take($limit)
            ->values()
            ->map(function ($item) {
                // created_at 필드 제거 (정렬용으로만 사용)
                unset($item['created_at']);

                return $item;
            })
            ->toArray();

        return [
            'items' => $sortedIssues,
            'total_count' => $issues->count(),
        ];
    }

    /**
     * 수주 성공 이슈 (최근 7일 확정 수주)
     */
    private function getOrderSuccessIssues(int $tenantId, Carbon $today): array
    {
        $orders = Order::query()
            ->where('tenant_id', $tenantId)
            ->where('status_code', 'confirmed')
            ->where('created_at', '>=', $today->copy()->subDays(7))
            ->with('client:id,name')
            ->orderByDesc('created_at')
            ->limit(10)
            ->get();

        return $orders->map(function ($order) {
            $clientName = $order->client?->name ?? __('message.today_issue.unknown_client');
            $amount = number_format($order->total_amount ?? 0);

            return [
                'id' => 'order_'.$order->id,
                'badge' => '수주 성공',
                'content' => __('message.today_issue.order_success', [
                    'client' => $clientName,
                    'amount' => $amount,
                ]),
                'time' => $this->formatRelativeTime($order->created_at),
                'date' => $order->created_at?->toDateString(),
                'needsApproval' => false,
                'path' => '/sales/order-management-sales',
                'created_at' => $order->created_at,
            ];
        })->toArray();
    }

    /**
     * 미수금 이슈 (주식 이슈 - 연체 미수금)
     */
    private function getReceivableIssues(int $tenantId): array
    {
        // BadDebt 모델에서 추심 진행 중인 건 조회
        $badDebts = BadDebt::query()
            ->where('tenant_id', $tenantId)
            ->whereIn('status', ['in_progress', 'legal_action'])
            ->with('client:id,name')
            ->orderByDesc('created_at')
            ->limit(10)
            ->get();

        return $badDebts->map(function ($debt) {
            $clientName = $debt->client?->name ?? __('message.today_issue.unknown_client');
            $amount = number_format($debt->total_amount ?? 0);
            $days = $debt->overdue_days ?? 0;

            return [
                'id' => 'receivable_'.$debt->id,
                'badge' => '주식 이슈',
                'content' => __('message.today_issue.receivable_overdue', [
                    'client' => $clientName,
                    'amount' => $amount,
                    'days' => $days,
                ]),
                'time' => $this->formatRelativeTime($debt->created_at),
                'date' => $debt->created_at?->toDateString(),
                'needsApproval' => false,
                'path' => '/accounting/receivables-status',
                'created_at' => $debt->created_at,
            ];
        })->toArray();
    }

    /**
     * 재고 이슈 (직정 제고 - 안전재고 미달)
     */
    private function getStockIssues(int $tenantId): array
    {
        $stocks = Stock::query()
            ->where('tenant_id', $tenantId)
            ->where('safety_stock', '>', 0)
            ->whereColumn('stock_qty', '<', 'safety_stock')
            ->with('item:id,name,code')
            ->orderByDesc('updated_at')
            ->limit(10)
            ->get();

        return $stocks->map(function ($stock) {
            $itemName = $stock->item?->name ?? $stock->item?->code ?? __('message.today_issue.unknown_item');

            return [
                'id' => 'stock_'.$stock->id,
                'badge' => '직정 제고',
                'content' => __('message.today_issue.stock_below_safety', [
                    'item' => $itemName,
                ]),
                'time' => $this->formatRelativeTime($stock->updated_at),
                'date' => $stock->updated_at?->toDateString(),
                'needsApproval' => false,
                'path' => '/material/stock-status',
                'created_at' => $stock->updated_at,
            ];
        })->toArray();
    }

    /**
     * 지출예상내역서 이슈 (승인 대기)
     */
    private function getExpectedExpenseIssues(int $tenantId): array
    {
        $expenses = ExpectedExpense::query()
            ->where('tenant_id', $tenantId)
            ->where('payment_status', 'pending')
            ->orderByDesc('created_at')
            ->limit(10)
            ->get();

        // 그룹화: 같은 날짜의 품의서들을 묶어서 표시
        if ($expenses->isEmpty()) {
            return [];
        }

        $totalCount = $expenses->count();
        $totalAmount = $expenses->sum('amount');
        $firstExpense = $expenses->first();
        $title = $firstExpense->description ?? __('message.today_issue.expense_item');

        $content = $totalCount > 1
            ? __('message.today_issue.expense_pending_multiple', [
                'title' => $title,
                'count' => $totalCount - 1,
                'amount' => number_format($totalAmount),
            ])
            : __('message.today_issue.expense_pending_single', [
                'title' => $title,
                'amount' => number_format($totalAmount),
            ]);

        return [
            [
                'id' => 'expense_summary',
                'badge' => '지출예상내역서',
                'content' => $content,
                'time' => $this->formatRelativeTime($firstExpense->created_at),
                'date' => $firstExpense->created_at?->toDateString(),
                'needsApproval' => true,
                'path' => '/approval/inbox',
                'created_at' => $firstExpense->created_at,
            ],
        ];
    }

    /**
     * 세금 신고 이슈 (부가세 D-day)
     */
    private function getTaxIssues(int $tenantId, Carbon $today): array
    {
        // 부가세 신고 마감일 계산 (분기별: 1/25, 4/25, 7/25, 10/25)
        $quarter = $today->quarter;
        $deadlineMonth = match ($quarter) {
            1 => 1,
            2 => 4,
            3 => 7,
            4 => 10,
        };

        $deadlineYear = $today->year;
        if ($today->month > $deadlineMonth || ($today->month == $deadlineMonth && $today->day > 25)) {
            $deadlineMonth = match ($quarter) {
                1 => 4,
                2 => 7,
                3 => 10,
                4 => 1,
            };
            if ($deadlineMonth == 1) {
                $deadlineYear++;
            }
        }

        $deadline = Carbon::create($deadlineYear, $deadlineMonth, 25);
        $daysUntil = $today->diffInDays($deadline, false);

        // D-30 이내인 경우에만 표시
        if ($daysUntil > 30 || $daysUntil < 0) {
            return [];
        }

        $quarterName = match ($deadlineMonth) {
            1 => '4',
            4 => '1',
            7 => '2',
            10 => '3',
        };

        return [
            [
                'id' => 'tax_vat_'.$deadlineYear.'_'.$deadlineMonth,
                'badge' => '세금 신고',
                'content' => __('message.today_issue.tax_vat_deadline', [
                    'quarter' => $quarterName,
                    'days' => $daysUntil,
                ]),
                'time' => $this->formatRelativeTime($today),
                'date' => $today->toDateString(),
                'needsApproval' => false,
                'path' => '/accounting/tax',
                'created_at' => $today,
            ],
        ];
    }

    /**
     * 결재 요청 이슈 (내 결재 대기 건)
     */
    private function getApprovalIssues(int $tenantId, int $userId): array
    {
        $steps = ApprovalStep::query()
            ->whereHas('approval', function ($query) use ($tenantId) {
                $query->where('tenant_id', $tenantId)
                    ->where('status', 'pending');
            })
            ->where('approver_id', $userId)
            ->where('status', 'pending')
            ->with(['approval' => function ($query) {
                $query->with('drafter:id,name');
            }])
            ->orderByDesc('created_at')
            ->limit(10)
            ->get();

        return $steps->map(function ($step) {
            $drafterName = $step->approval->drafter?->name ?? __('message.today_issue.unknown_user');
            $title = $step->approval->title ?? __('message.today_issue.approval_request');

            return [
                'id' => 'approval_'.$step->approval->id,
                'badge' => '결재 요청',
                'content' => __('message.today_issue.approval_pending', [
                    'title' => $title,
                    'drafter' => $drafterName,
                ]),
                'time' => $this->formatRelativeTime($step->approval->created_at),
                'date' => $step->approval->created_at?->toDateString(),
                'needsApproval' => true,
                'path' => '/approval/inbox',
                'created_at' => $step->approval->created_at,
            ];
        })->toArray();
    }

    /**
     * 기타 이슈 (신규 거래처 등록 등)
     */
    private function getOtherIssues(int $tenantId, Carbon $today): array
    {
        // 최근 7일 신규 거래처
        $clients = Client::query()
            ->where('tenant_id', $tenantId)
            ->where('created_at', '>=', $today->copy()->subDays(7))
            ->orderByDesc('created_at')
            ->limit(5)
            ->get();

        return $clients->map(function ($client) {
            return [
                'id' => 'client_'.$client->id,
                'badge' => '기타',
                'content' => __('message.today_issue.new_client', [
                    'name' => $client->name,
                ]),
                'time' => $this->formatRelativeTime($client->created_at),
                'date' => $client->created_at?->toDateString(),
                'needsApproval' => false,
                'path' => '/accounting/vendors',
                'created_at' => $client->created_at,
            ];
        })->toArray();
    }

    /**
     * 상대 시간 포맷팅
     */
    private function formatRelativeTime(?Carbon $datetime): string
    {
        if (! $datetime) {
            return '';
        }

        $now = Carbon::now();
        $diffInMinutes = $now->diffInMinutes($datetime);
        $diffInHours = $now->diffInHours($datetime);
        $diffInDays = $now->diffInDays($datetime);

        if ($diffInMinutes < 60) {
            return __('message.today_issue.time_minutes_ago', ['minutes' => max(1, $diffInMinutes)]);
        }

        if ($diffInHours < 24) {
            return __('message.today_issue.time_hours_ago', ['hours' => $diffInHours]);
        }

        if ($diffInDays == 1) {
            return __('message.today_issue.time_yesterday');
        }

        if ($diffInDays < 7) {
            return __('message.today_issue.time_days_ago', ['days' => $diffInDays]);
        }

        return $datetime->format('Y-m-d');
    }
}