<?php

namespace App\Services;

use App\Models\Stats\Monthly\StatFinanceMonthly;
use App\Models\Stats\Monthly\StatSalesMonthly;
use App\Models\Tenants\Approval;
use App\Models\Tenants\ApprovalStep;
use App\Models\Tenants\Attendance;
use App\Models\Tenants\Deposit;
use App\Models\Tenants\Leave;
use App\Models\Tenants\Purchase;
use App\Models\Tenants\Sale;
use App\Models\Tenants\Withdrawal;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class DashboardService extends Service
{
    /**
     * 대시보드 요약 데이터 조회
     */
    public function summary(): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();
        $today = Carbon::today();
        $startOfMonth = Carbon::now()->startOfMonth();
        $endOfMonth = Carbon::now()->endOfMonth();

        return [
            'today' => $this->getTodaySummary($tenantId, $today),
            'finance' => $this->getFinanceSummary($tenantId, $startOfMonth, $endOfMonth),
            'sales' => $this->getSalesSummary($tenantId, $startOfMonth, $endOfMonth),
            'tasks' => $this->getTasksSummary($tenantId, $userId),
        ];
    }

    /**
     * 대시보드 차트 데이터 조회
     *
     * @param  array  $params  [period: week|month|quarter]
     */
    public function charts(array $params): array
    {
        $tenantId = $this->tenantId();
        $period = $params['period'] ?? 'month';

        [$startDate, $endDate] = $this->getPeriodRange($period);

        return [
            'period' => $period,
            'start_date' => $startDate->toDateString(),
            'end_date' => $endDate->toDateString(),
            'deposit_trend' => $this->getDepositTrend($tenantId, $startDate, $endDate),
            'withdrawal_trend' => $this->getWithdrawalTrend($tenantId, $startDate, $endDate),
            'sales_by_client' => $this->getSalesByClient($tenantId, $startDate, $endDate),
        ];
    }

    /**
     * 결재 현황 조회
     *
     * @param  array  $params  [limit: int]
     */
    public function approvals(array $params): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();
        $limit = $params['limit'] ?? 10;

        // 내가 결재할 문서 (결재함)
        $pendingApprovals = $this->getPendingApprovals($tenantId, $userId, $limit);

        // 내가 기안한 문서 중 진행중인 것
        $myDrafts = $this->getMyPendingDrafts($tenantId, $userId, $limit);

        return [
            'pending_approvals' => $pendingApprovals,
            'my_drafts' => $myDrafts,
        ];
    }

    /**
     * 오늘 요약 데이터
     */
    private function getTodaySummary(int $tenantId, Carbon $today): array
    {
        // 오늘 출근자 수
        $attendancesCount = Attendance::query()
            ->where('tenant_id', $tenantId)
            ->whereDate('work_date', $today)
            ->whereNotNull('check_in')
            ->count();

        // 오늘 휴가자 수
        $leavesCount = Leave::query()
            ->where('tenant_id', $tenantId)
            ->where('status', 'approved')
            ->whereDate('start_date', '<=', $today)
            ->whereDate('end_date', '>=', $today)
            ->count();

        // 결재 대기 문서 수 (전체)
        $approvalsPending = Approval::query()
            ->where('tenant_id', $tenantId)
            ->where('status', 'pending')
            ->count();

        return [
            'date' => $today->toDateString(),
            'attendances_count' => $attendancesCount,
            'leaves_count' => $leavesCount,
            'approvals_pending' => $approvalsPending,
        ];
    }

    /**
     * 재무 요약 데이터 (sam_stat 우선, 폴백: 원본 DB)
     */
    private function getFinanceSummary(int $tenantId, Carbon $startOfMonth, Carbon $endOfMonth): array
    {
        // sam_stat 월간 데이터 시도
        $monthly = StatFinanceMonthly::where('tenant_id', $tenantId)
            ->where('stat_year', $startOfMonth->year)
            ->where('stat_month', $startOfMonth->month)
            ->first();

        if ($monthly) {
            return [
                'monthly_deposit' => (float) $monthly->deposit_amount,
                'monthly_withdrawal' => (float) $monthly->withdrawal_amount,
                'balance' => (float) ($monthly->deposit_amount - $monthly->withdrawal_amount),
                'source' => 'sam_stat',
            ];
        }

        // 폴백: 원본 DB 실시간 집계
        $monthlyDeposit = Deposit::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('deposit_date', [$startOfMonth, $endOfMonth])
            ->sum('amount');

        $monthlyWithdrawal = Withdrawal::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('withdrawal_date', [$startOfMonth, $endOfMonth])
            ->sum('amount');

        $totalDeposits = Deposit::query()
            ->where('tenant_id', $tenantId)
            ->sum('amount');

        $totalWithdrawals = Withdrawal::query()
            ->where('tenant_id', $tenantId)
            ->sum('amount');

        $balance = $totalDeposits - $totalWithdrawals;

        return [
            'monthly_deposit' => (float) $monthlyDeposit,
            'monthly_withdrawal' => (float) $monthlyWithdrawal,
            'balance' => (float) $balance,
            'source' => 'samdb',
        ];
    }

    /**
     * 매출/매입 요약 데이터 (sam_stat 우선, 폴백: 원본 DB)
     */
    private function getSalesSummary(int $tenantId, Carbon $startOfMonth, Carbon $endOfMonth): array
    {
        // sam_stat 월간 데이터 시도
        $monthly = StatSalesMonthly::where('tenant_id', $tenantId)
            ->where('stat_year', $startOfMonth->year)
            ->where('stat_month', $startOfMonth->month)
            ->first();

        if ($monthly) {
            return [
                'monthly_sales' => (float) $monthly->sales_amount,
                'monthly_purchases' => 0,
                'source' => 'sam_stat',
            ];
        }

        // 폴백: 원본 DB 실시간 집계
        $monthlySales = Sale::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('sale_date', [$startOfMonth, $endOfMonth])
            ->sum('total_amount');

        $monthlyPurchases = Purchase::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('purchase_date', [$startOfMonth, $endOfMonth])
            ->sum('total_amount');

        return [
            'monthly_sales' => (float) $monthlySales,
            'monthly_purchases' => (float) $monthlyPurchases,
            'source' => 'samdb',
        ];
    }

    /**
     * 할 일 요약 데이터
     */
    private function getTasksSummary(int $tenantId, int $userId): array
    {
        // 내가 결재해야 할 문서 수
        $pendingApprovals = ApprovalStep::query()
            ->whereHas('approval', function ($query) use ($tenantId) {
                $query->where('tenant_id', $tenantId)
                    ->where('status', 'pending');
            })
            ->where('approver_id', $userId)
            ->where('status', 'pending')
            ->count();

        // 승인 대기 휴가 신청 수 (관리자용)
        $pendingLeaves = Leave::query()
            ->where('tenant_id', $tenantId)
            ->where('status', 'pending')
            ->count();

        return [
            'pending_approvals' => $pendingApprovals,
            'pending_leaves' => $pendingLeaves,
        ];
    }

    /**
     * 기간 범위 계산
     *
     * @return array [Carbon $startDate, Carbon $endDate]
     */
    private function getPeriodRange(string $period): array
    {
        $endDate = Carbon::today();

        switch ($period) {
            case 'week':
                $startDate = $endDate->copy()->subDays(6);
                break;
            case 'quarter':
                $startDate = $endDate->copy()->subMonths(3)->startOfMonth();
                break;
            case 'month':
            default:
                $startDate = $endDate->copy()->subDays(29);
                break;
        }

        return [$startDate, $endDate];
    }

    /**
     * 입금 추이 데이터
     */
    private function getDepositTrend(int $tenantId, Carbon $startDate, Carbon $endDate): array
    {
        $deposits = Deposit::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('deposit_date', [$startDate, $endDate])
            ->select(
                DB::raw('DATE(deposit_date) as date'),
                DB::raw('SUM(amount) as amount')
            )
            ->groupBy(DB::raw('DATE(deposit_date)'))
            ->orderBy('date')
            ->get();

        return $deposits->map(function ($item) {
            return [
                'date' => $item->date,
                'amount' => (float) $item->amount,
            ];
        })->toArray();
    }

    /**
     * 출금 추이 데이터
     */
    private function getWithdrawalTrend(int $tenantId, Carbon $startDate, Carbon $endDate): array
    {
        $withdrawals = Withdrawal::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('withdrawal_date', [$startDate, $endDate])
            ->select(
                DB::raw('DATE(withdrawal_date) as date'),
                DB::raw('SUM(amount) as amount')
            )
            ->groupBy(DB::raw('DATE(withdrawal_date)'))
            ->orderBy('date')
            ->get();

        return $withdrawals->map(function ($item) {
            return [
                'date' => $item->date,
                'amount' => (float) $item->amount,
            ];
        })->toArray();
    }

    /**
     * 거래처별 매출 데이터
     */
    private function getSalesByClient(int $tenantId, Carbon $startDate, Carbon $endDate): array
    {
        $sales = Sale::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('sale_date', [$startDate, $endDate])
            ->with('client:id,name')
            ->select(
                'client_id',
                DB::raw('SUM(total_amount) as amount')
            )
            ->groupBy('client_id')
            ->orderByDesc('amount')
            ->limit(10)
            ->get();

        return $sales->map(function ($item) {
            return [
                'client_id' => $item->client_id,
                'client_name' => $item->client?->name ?? __('message.dashboard.unknown_client'),
                'amount' => (float) $item->amount,
            ];
        })->toArray();
    }

    /**
     * 내가 결재해야 할 문서 목록
     */
    private function getPendingApprovals(int $tenantId, int $userId, int $limit): 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');
            }])
            ->orderBy('created_at', 'desc')
            ->limit($limit)
            ->get();

        return $steps->map(function ($step) {
            return [
                'id' => $step->approval->id,
                'title' => $step->approval->title,
                'drafter_name' => $step->approval->drafter?->name ?? '',
                'status' => $step->approval->status,
                'created_at' => $step->approval->created_at?->toDateTimeString(),
            ];
        })->toArray();
    }

    /**
     * 내가 기안한 진행중인 문서 목록
     */
    private function getMyPendingDrafts(int $tenantId, int $userId, int $limit): array
    {
        $approvals = Approval::query()
            ->where('tenant_id', $tenantId)
            ->where('drafter_id', $userId)
            ->where('status', 'pending')
            ->orderBy('created_at', 'desc')
            ->limit($limit)
            ->get();

        return $approvals->map(function ($approval) {
            return [
                'id' => $approval->id,
                'title' => $approval->title,
                'status' => $approval->status,
                'current_step' => $approval->current_step,
                'created_at' => $approval->created_at?->toDateTimeString(),
            ];
        })->toArray();
    }
}
