<?php

namespace App\Services;

use App\Models\Tenants\ExpectedExpense;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

class ExpectedExpenseService extends Service
{
    /**
     * 미지급비용 목록 조회
     */
    public function index(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        $query = ExpectedExpense::query()
            ->where('tenant_id', $tenantId)
            ->with(['client:id,name', 'bankAccount:id,bank_name,account_name']);

        // 검색어 필터
        if (! empty($params['search'])) {
            $search = $params['search'];
            $query->where(function ($q) use ($search) {
                $q->where('client_name', 'like', "%{$search}%")
                    ->orWhere('account_code', 'like', "%{$search}%")
                    ->orWhere('description', 'like', "%{$search}%")
                    ->orWhereHas('client', function ($q) use ($search) {
                        $q->where('name', 'like', "%{$search}%");
                    });
            });
        }

        // 날짜 범위 필터 (예상 지급일 기준)
        if (! empty($params['start_date'])) {
            $query->where('expected_payment_date', '>=', $params['start_date']);
        }
        if (! empty($params['end_date'])) {
            $query->where('expected_payment_date', '<=', $params['end_date']);
        }

        // 거래처 필터
        if (! empty($params['client_id'])) {
            $query->where('client_id', $params['client_id']);
        }

        // 거래유형 필터
        if (! empty($params['transaction_type'])) {
            $query->where('transaction_type', $params['transaction_type']);
        }

        // 지급상태 필터
        if (! empty($params['payment_status'])) {
            $query->where('payment_status', $params['payment_status']);
        }

        // 결재상태 필터
        if (! empty($params['approval_status'])) {
            $query->where('approval_status', $params['approval_status']);
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'expected_payment_date';
        $sortDir = $params['sort_dir'] ?? 'asc';
        $query->orderBy($sortBy, $sortDir);

        // 페이지네이션
        $perPage = $params['per_page'] ?? 50;

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

    /**
     * 미지급비용 상세 조회
     */
    public function show(int $id): ExpectedExpense
    {
        $tenantId = $this->tenantId();

        return ExpectedExpense::query()
            ->where('tenant_id', $tenantId)
            ->with(['client:id,name', 'bankAccount:id,bank_name,account_name', 'creator:id,name'])
            ->findOrFail($id);
    }

    /**
     * 미지급비용 등록
     */
    public function store(array $data): ExpectedExpense
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($data, $tenantId, $userId) {
            $expense = new ExpectedExpense;
            $expense->tenant_id = $tenantId;
            $expense->expected_payment_date = $data['expected_payment_date'];
            $expense->settlement_date = $data['settlement_date'] ?? null;
            $expense->transaction_type = $data['transaction_type'];
            $expense->amount = $data['amount'];
            $expense->client_id = $data['client_id'] ?? null;
            $expense->client_name = $data['client_name'] ?? null;
            $expense->bank_account_id = $data['bank_account_id'] ?? null;
            $expense->account_code = $data['account_code'] ?? null;
            $expense->payment_status = $data['payment_status'] ?? 'pending';
            $expense->approval_status = $data['approval_status'] ?? 'none';
            $expense->description = $data['description'] ?? null;
            $expense->created_by = $userId;
            $expense->updated_by = $userId;
            $expense->save();

            return $expense->load(['client:id,name', 'bankAccount:id,bank_name,account_name']);
        });
    }

    /**
     * 미지급비용 수정
     */
    public function update(int $id, array $data): ExpectedExpense
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $data, $tenantId, $userId) {
            $expense = ExpectedExpense::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            if (isset($data['expected_payment_date'])) {
                $expense->expected_payment_date = $data['expected_payment_date'];
            }
            if (array_key_exists('settlement_date', $data)) {
                $expense->settlement_date = $data['settlement_date'];
            }
            if (isset($data['transaction_type'])) {
                $expense->transaction_type = $data['transaction_type'];
            }
            if (isset($data['amount'])) {
                $expense->amount = $data['amount'];
            }
            if (array_key_exists('client_id', $data)) {
                $expense->client_id = $data['client_id'];
            }
            if (array_key_exists('client_name', $data)) {
                $expense->client_name = $data['client_name'];
            }
            if (array_key_exists('bank_account_id', $data)) {
                $expense->bank_account_id = $data['bank_account_id'];
            }
            if (array_key_exists('account_code', $data)) {
                $expense->account_code = $data['account_code'];
            }
            if (isset($data['payment_status'])) {
                $expense->payment_status = $data['payment_status'];
            }
            if (isset($data['approval_status'])) {
                $expense->approval_status = $data['approval_status'];
            }
            if (array_key_exists('description', $data)) {
                $expense->description = $data['description'];
            }

            $expense->updated_by = $userId;
            $expense->save();

            return $expense->fresh(['client:id,name', 'bankAccount:id,bank_name,account_name']);
        });
    }

    /**
     * 미지급비용 삭제
     */
    public function destroy(int $id): bool
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $tenantId, $userId) {
            $expense = ExpectedExpense::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            $expense->deleted_by = $userId;
            $expense->save();
            $expense->delete();

            return true;
        });
    }

    /**
     * 일괄 삭제
     */
    public function destroyMany(array $ids): int
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($ids, $tenantId, $userId) {
            $count = 0;
            foreach ($ids as $id) {
                $expense = ExpectedExpense::query()
                    ->where('tenant_id', $tenantId)
                    ->find($id);

                if ($expense) {
                    $expense->deleted_by = $userId;
                    $expense->save();
                    $expense->delete();
                    $count++;
                }
            }

            return $count;
        });
    }

    /**
     * 예상 지급일 일괄 변경
     */
    public function updateExpectedPaymentDate(array $ids, string $newDate): int
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($ids, $newDate, $tenantId, $userId) {
            return ExpectedExpense::query()
                ->where('tenant_id', $tenantId)
                ->whereIn('id', $ids)
                ->update([
                    'expected_payment_date' => $newDate,
                    'updated_by' => $userId,
                ]);
        });
    }

    /**
     * 미지급비용 요약 (기간별 합계)
     */
    public function summary(array $params): array
    {
        $tenantId = $this->tenantId();

        $query = ExpectedExpense::query()
            ->where('tenant_id', $tenantId);

        // 날짜 범위 필터
        if (! empty($params['start_date'])) {
            $query->where('expected_payment_date', '>=', $params['start_date']);
        }
        if (! empty($params['end_date'])) {
            $query->where('expected_payment_date', '<=', $params['end_date']);
        }

        // 지급상태 필터
        if (! empty($params['payment_status'])) {
            $query->where('payment_status', $params['payment_status']);
        }

        // 전체 합계
        $total = (clone $query)->sum('amount');
        $count = (clone $query)->count();

        // 지급상태별 합계
        $byPaymentStatus = (clone $query)
            ->select('payment_status', DB::raw('SUM(amount) as total'), DB::raw('COUNT(*) as count'))
            ->groupBy('payment_status')
            ->get()
            ->keyBy('payment_status')
            ->toArray();

        // 거래유형별 합계
        $byTransactionType = (clone $query)
            ->select('transaction_type', DB::raw('SUM(amount) as total'), DB::raw('COUNT(*) as count'))
            ->groupBy('transaction_type')
            ->get()
            ->keyBy('transaction_type')
            ->toArray();

        // 월별 합계
        $byMonth = (clone $query)
            ->select(
                DB::raw("DATE_FORMAT(expected_payment_date, '%Y-%m') as month"),
                DB::raw('SUM(amount) as total'),
                DB::raw('COUNT(*) as count')
            )
            ->groupBy('month')
            ->orderBy('month')
            ->get()
            ->keyBy('month')
            ->toArray();

        return [
            'total_amount' => (float) $total,
            'total_count' => $count,
            'by_payment_status' => $byPaymentStatus,
            'by_transaction_type' => $byTransactionType,
            'by_month' => $byMonth,
        ];
    }

    /**
     * 대시보드 상세 조회 (CEO 대시보드 당월 예상 지출내역 모달용)
     *
     * @param  string|null  $transactionType  거래유형 필터 (purchase, card, bill, null=전체)
     * @param  string|null  $startDate  조회 시작일 (null이면 당월 1일)
     * @param  string|null  $endDate    조회 종료일 (null이면 당월 말일)
     * @param  string|null  $search     검색어 (거래처명, 적요)
     */
    public function dashboardDetail(
        ?string $transactionType = null,
        ?string $startDate = null,
        ?string $endDate = null,
        ?string $search = null
    ): array {
        $tenantId = $this->tenantId();

        // 날짜 범위: 파라미터 우선, 없으면 당월 기본값
        $currentMonthStart = $startDate ?? now()->startOfMonth()->toDateString();
        $currentMonthEnd = $endDate ?? now()->endOfMonth()->toDateString();

        // 전월 대비: 조회 기간과 동일한 길이의 이전 기간 계산
        $startCarbon = \Carbon\Carbon::parse($currentMonthStart);
        $endCarbon = \Carbon\Carbon::parse($currentMonthEnd);
        $daysDiff = $startCarbon->diffInDays($endCarbon) + 1;
        $previousMonthStart = $startCarbon->copy()->subDays($daysDiff)->toDateString();
        $previousMonthEnd = $startCarbon->copy()->subDay()->toDateString();

        // 기본 쿼리 빌더 (transaction_type + search 필터 적용)
        $baseQuery = function () use ($tenantId, $transactionType, $search) {
            $query = ExpectedExpense::query()->where('tenant_id', $tenantId);
            if ($transactionType) {
                $query->where('transaction_type', $transactionType);
            }
            if ($search) {
                $query->where(function ($q) use ($search) {
                    $q->where('client_name', 'like', "%{$search}%")
                        ->orWhere('description', 'like', "%{$search}%");
                });
            }

            return $query;
        };

        // 1. 요약 정보
        $currentMonthTotal = $baseQuery()
            ->whereBetween('expected_payment_date', [$currentMonthStart, $currentMonthEnd])
            ->sum('amount');

        $currentMonthCount = $baseQuery()
            ->whereBetween('expected_payment_date', [$currentMonthStart, $currentMonthEnd])
            ->count();

        $previousMonthTotal = $baseQuery()
            ->whereBetween('expected_payment_date', [$previousMonthStart, $previousMonthEnd])
            ->sum('amount');

        $changeRate = $previousMonthTotal > 0
            ? round((($currentMonthTotal - $previousMonthTotal) / $previousMonthTotal) * 100, 1)
            : ($currentMonthTotal > 0 ? 100 : 0);

        // 미지급 잔액 (pending 상태) - remaining_balance로 반환
        $pendingBalance = $baseQuery()
            ->where('payment_status', 'pending')
            ->sum('amount');

        // 2. 월별 추이 (최근 7개월)
        $monthlyTrend = $this->getMonthlyTrend($tenantId, $transactionType);

        // 3. 거래처별 분포 (조회 기간, 상위 5개)
        $vendorDistribution = $this->getVendorDistribution($tenantId, $transactionType, $currentMonthStart, $currentMonthEnd);

        // 4. 지출예상 목록 (조회 기간, 지급일 순)
        $itemsQuery = ExpectedExpense::query()
            ->select([
                'expected_expenses.id',
                'expected_expenses.expected_payment_date',
                'expected_expenses.description',
                'expected_expenses.amount',
                'expected_expenses.client_id',
                'expected_expenses.client_name',
                'expected_expenses.account_code',
                'expected_expenses.payment_status',
                'expected_expenses.transaction_type',
            ])
            ->leftJoin('clients', 'expected_expenses.client_id', '=', 'clients.id')
            ->where('expected_expenses.tenant_id', $tenantId)
            ->whereBetween('expected_expenses.expected_payment_date', [$currentMonthStart, $currentMonthEnd]);

        if ($transactionType) {
            $itemsQuery->where('expected_expenses.transaction_type', $transactionType);
        }

        if ($search) {
            $itemsQuery->where(function ($q) use ($search) {
                $q->where('expected_expenses.client_name', 'like', "%{$search}%")
                    ->orWhere('expected_expenses.description', 'like', "%{$search}%");
            });
        }

        $items = $itemsQuery
            ->orderBy('expected_expenses.expected_payment_date', 'asc')
            ->get()
            ->map(function ($item) {
                return [
                    'id' => $item->id,
                    'payment_date' => $item->expected_payment_date?->format('Y-m-d'),
                    'item_name' => $item->description ?? '',
                    'amount' => (float) $item->amount,
                    'vendor_name' => $item->client_name ?? '',
                    'account_title' => $item->account_code ?? '',
                    'status' => $item->payment_status,
                    'transaction_type' => $item->transaction_type,
                ];
            })
            ->toArray();

        // 5. 푸터 합계
        $footerSummary = [
            'total_amount' => (float) $currentMonthTotal,
            'item_count' => count($items),
        ];

        return [
            'summary' => [
                'total_amount' => (float) $currentMonthTotal,
                'previous_month_amount' => (float) $previousMonthTotal,
                'change_rate' => $changeRate,
                'remaining_balance' => (float) $pendingBalance,
            ],
            'monthly_trend' => $monthlyTrend,
            'vendor_distribution' => $vendorDistribution,
            'items' => $items,
            'footer_summary' => $footerSummary,
        ];
    }

    /**
     * 월별 추이 데이터 조회 (최근 7개월)
     */
    private function getMonthlyTrend(int $tenantId, ?string $transactionType = null): array
    {
        $months = [];
        for ($i = 6; $i >= 0; $i--) {
            $date = now()->subMonths($i);
            $months[] = [
                'month' => $date->format('Y-m'),
                'label' => $date->format('n').'월',
                'start' => $date->startOfMonth()->toDateString(),
                'end' => $date->endOfMonth()->toDateString(),
            ];
        }

        $result = [];
        foreach ($months as $month) {
            $query = ExpectedExpense::query()
                ->where('tenant_id', $tenantId)
                ->whereBetween('expected_payment_date', [$month['start'], $month['end']]);

            if ($transactionType) {
                $query->where('transaction_type', $transactionType);
            }

            $amount = $query->sum('amount');

            $result[] = [
                'month' => $month['month'],
                'label' => $month['label'],
                'amount' => (float) $amount,
            ];
        }

        return $result;
    }

    /**
     * 거래처별 분포 데이터 조회 (상위 N개 + 기타)
     */
    private function getVendorDistribution(int $tenantId, ?string $transactionType, string $startDate, string $endDate, int $limit = 5): array
    {
        $query = ExpectedExpense::query()
            ->select(
                DB::raw("COALESCE(client_name, '미지정') as vendor_name"),
                DB::raw('SUM(amount) as total_amount'),
                DB::raw('COUNT(*) as count')
            )
            ->where('tenant_id', $tenantId)
            ->whereBetween('expected_payment_date', [$startDate, $endDate])
            ->groupBy('client_name')
            ->orderByDesc('total_amount');

        if ($transactionType) {
            $query->where('transaction_type', $transactionType);
        }

        $all = $query->get();

        // 전체 합계
        $totalSum = $all->sum('total_amount');
        if ($totalSum <= 0) {
            return [];
        }

        // 상위 N개
        $top = $all->take($limit);
        $topSum = $top->sum('total_amount');

        // 색상 팔레트
        $colors = ['#60A5FA', '#34D399', '#FBBF24', '#F87171', '#A78BFA', '#94A3B8'];

        $result = [];
        foreach ($top as $index => $item) {
            $percentage = round(($item->total_amount / $totalSum) * 100, 1);
            $result[] = [
                'name' => $item->vendor_name,
                'value' => (float) $item->total_amount,
                'count' => (int) $item->count,
                'percentage' => $percentage,
                'color' => $colors[$index] ?? '#94A3B8',
            ];
        }

        // 기타 (나머지 합산)
        $othersSum = $totalSum - $topSum;
        if ($othersSum > 0 && $all->count() > $limit) {
            $othersCount = $all->skip($limit)->sum('count');
            $result[] = [
                'name' => '기타',
                'value' => (float) $othersSum,
                'count' => (int) $othersCount,
                'percentage' => round(($othersSum / $totalSum) * 100, 1),
                'color' => '#94A3B8',
            ];
        }

        return $result;
    }
}
