<?php

namespace App\Http\Controllers\Api\Admin\Barobill;

use App\Http\Controllers\Controller;
use App\Models\Barobill\BarobillBillingRecord;
use App\Models\Barobill\BarobillMember;
use App\Models\Barobill\BarobillMonthlySummary;
use App\Models\Barobill\BarobillPricingPolicy;
use App\Models\Barobill\BarobillSubscription;
use App\Services\Barobill\BarobillBillingService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

/**
 * 바로빌 과금 관리 API 컨트롤러
 */
class BarobillBillingController extends Controller
{
    private const HEADQUARTERS_TENANT_ID = 1;

    public function __construct(
        protected BarobillBillingService $billingService
    ) {}

    // ========================================
    // 구독 관리
    // ========================================

    /**
     * 구독 목록 조회
     */
    public function subscriptions(Request $request): JsonResponse|Response
    {
        $tenantId = session('selected_tenant_id');
        $isHeadquarters = $tenantId == self::HEADQUARTERS_TENANT_ID;
        $allTenants = $request->boolean('all_tenants', false);

        $query = BarobillSubscription::with(['member.tenant'])
            ->orderBy('member_id')
            ->orderBy('service_type');

        // 테넌트 필터링
        if (! $isHeadquarters && ! $allTenants) {
            $query->whereHas('member', function ($q) use ($tenantId) {
                $q->where('tenant_id', $tenantId);
            });
        }

        $subscriptions = $query->get();

        if ($request->header('HX-Request')) {
            return response(
                view('barobill.billing.partials.subscription-table', [
                    'subscriptions' => $subscriptions,
                    'allTenants' => $isHeadquarters || $allTenants,
                ])->render(),
                200,
                ['Content-Type' => 'text/html']
            );
        }

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

    /**
     * 구독 등록/수정
     */
    public function saveSubscription(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'member_id' => 'required|exists:barobill_members,id',
            'service_type' => 'required|in:bank_account,card,hometax',
            'monthly_fee' => 'nullable|integer|min:0',
            'started_at' => 'nullable|date',
            'ended_at' => 'nullable|date|after_or_equal:started_at',
            'is_active' => 'nullable|boolean',
            'memo' => 'nullable|string|max:500',
        ]);

        $subscription = $this->billingService->saveSubscription(
            $validated['member_id'],
            $validated['service_type'],
            $validated
        );

        return response()->json([
            'success' => true,
            'message' => '구독이 저장되었습니다.',
            'data' => $subscription,
        ]);
    }

    /**
     * 구독 해지
     */
    public function cancelSubscription(int $id): JsonResponse
    {
        $result = $this->billingService->cancelSubscription($id);

        if (! $result) {
            return response()->json([
                'success' => false,
                'message' => '구독을 찾을 수 없습니다.',
            ], 404);
        }

        return response()->json([
            'success' => true,
            'message' => '구독이 해지되었습니다.',
        ]);
    }

    /**
     * 회원사별 구독 현황 조회
     */
    public function memberSubscriptions(int $memberId): JsonResponse|Response
    {
        $member = BarobillMember::with('tenant')->find($memberId);
        if (! $member) {
            return response()->json([
                'success' => false,
                'message' => '회원사를 찾을 수 없습니다.',
            ], 404);
        }

        $subscriptions = BarobillSubscription::where('member_id', $memberId)
            ->orderBy('service_type')
            ->get();

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

    // ========================================
    // 과금 현황
    // ========================================

    /**
     * 월별 과금 현황 목록
     */
    public function billingList(Request $request): JsonResponse|Response
    {
        $tenantId = session('selected_tenant_id');
        $isHeadquarters = $tenantId == self::HEADQUARTERS_TENANT_ID;
        $allTenants = $request->boolean('all_tenants', false);

        $billingMonth = $request->input('billing_month', now()->format('Y-m'));

        // 테넌트 필터링
        $filterTenantId = (! $isHeadquarters && ! $allTenants) ? $tenantId : null;

        $summaries = BarobillMonthlySummary::with(['member.tenant'])
            ->where('billing_month', $billingMonth)
            ->when($filterTenantId, function ($q) use ($filterTenantId) {
                $q->whereHas('member', function ($q2) use ($filterTenantId) {
                    $q2->where('tenant_id', $filterTenantId);
                });
            })
            ->orderBy('grand_total', 'desc')
            ->get();

        $total = $this->billingService->getMonthlyTotal($billingMonth, $filterTenantId);

        if ($request->header('HX-Request')) {
            return response(
                view('barobill.billing.partials.billing-table', [
                    'summaries' => $summaries,
                    'total' => $total,
                    'billingMonth' => $billingMonth,
                    'allTenants' => $isHeadquarters || $allTenants,
                ])->render(),
                200,
                ['Content-Type' => 'text/html']
            );
        }

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

    /**
     * 월별 과금 통계
     */
    public function billingStats(Request $request): JsonResponse|Response
    {
        $tenantId = session('selected_tenant_id');
        $isHeadquarters = $tenantId == self::HEADQUARTERS_TENANT_ID;
        $allTenants = $request->boolean('all_tenants', false);

        $billingMonth = $request->input('billing_month', now()->format('Y-m'));

        $filterTenantId = (! $isHeadquarters && ! $allTenants) ? $tenantId : null;
        $stats = $this->billingService->getMonthlyTotal($billingMonth, $filterTenantId);

        if ($request->header('HX-Request')) {
            return response(
                view('barobill.billing.partials.billing-stats', compact('stats'))->render(),
                200,
                ['Content-Type' => 'text/html']
            );
        }

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

    /**
     * 회원사별 과금 상세
     */
    public function memberBilling(Request $request, int $memberId): JsonResponse|Response
    {
        $member = BarobillMember::with('tenant')->find($memberId);
        if (! $member) {
            return response()->json([
                'success' => false,
                'message' => '회원사를 찾을 수 없습니다.',
            ], 404);
        }

        $billingMonth = $request->input('billing_month', now()->format('Y-m'));

        $records = BarobillBillingRecord::where('member_id', $memberId)
            ->where('billing_month', $billingMonth)
            ->orderBy('service_type')
            ->get();

        $summary = BarobillMonthlySummary::where('member_id', $memberId)
            ->where('billing_month', $billingMonth)
            ->first();

        if ($request->header('HX-Request')) {
            return response(
                view('barobill.billing.partials.member-billing-detail', [
                    'member' => $member,
                    'records' => $records,
                    'summary' => $summary,
                    'billingMonth' => $billingMonth,
                ])->render(),
                200,
                ['Content-Type' => 'text/html']
            );
        }

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

    /**
     * 월별 과금 처리 (수동 실행)
     */
    public function processBilling(Request $request): JsonResponse
    {
        $billingMonth = $request->input('billing_month', now()->format('Y-m'));

        $result = $this->billingService->processMonthlyBilling($billingMonth);

        return response()->json([
            'success' => true,
            'message' => "과금 처리 완료: {$result['processed']}건 처리, {$result['skipped']}건 스킵",
            'data' => $result,
        ]);
    }

    /**
     * 연간 추이 조회
     */
    public function yearlyTrend(Request $request): JsonResponse
    {
        $tenantId = session('selected_tenant_id');
        $isHeadquarters = $tenantId == self::HEADQUARTERS_TENANT_ID;
        $allTenants = $request->boolean('all_tenants', false);

        $year = $request->input('year', now()->year);

        $filterTenantId = (! $isHeadquarters && ! $allTenants) ? $tenantId : null;
        $trend = $this->billingService->getYearlyTrend($year, $filterTenantId);

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

    /**
     * 엑셀 다운로드
     */
    public function export(Request $request)
    {
        $tenantId = session('selected_tenant_id');
        $isHeadquarters = $tenantId == self::HEADQUARTERS_TENANT_ID;
        $allTenants = $request->boolean('all_tenants', false);

        $billingMonth = $request->input('billing_month', now()->format('Y-m'));

        $filterTenantId = (! $isHeadquarters && ! $allTenants) ? $tenantId : null;

        $summaries = BarobillMonthlySummary::with(['member.tenant'])
            ->where('billing_month', $billingMonth)
            ->when($filterTenantId, function ($q) use ($filterTenantId) {
                $q->whereHas('member', function ($q2) use ($filterTenantId) {
                    $q2->where('tenant_id', $filterTenantId);
                });
            })
            ->orderBy('grand_total', 'desc')
            ->get();

        $total = $this->billingService->getMonthlyTotal($billingMonth, $filterTenantId);

        $filename = "barobill_billing_{$billingMonth}.csv";

        $headers = [
            'Content-Type' => 'text/csv; charset=UTF-8',
            'Content-Disposition' => "attachment; filename=\"{$filename}\"",
        ];

        $callback = function () use ($summaries, $total, $isHeadquarters, $allTenants) {
            $file = fopen('php://output', 'w');
            fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF));

            // 헤더
            $headerRow = ['사업자번호', '상호', '계좌조회', '카드내역', '홈텍스', '월정액합계', '세금계산서(건)', '세금계산서(원)', '건별합계', '총합계'];
            if ($isHeadquarters || $allTenants) {
                array_unshift($headerRow, 'T-ID', '테넌트');
            }
            fputcsv($file, $headerRow);

            // 데이터
            foreach ($summaries as $summary) {
                $row = [
                    $summary->member->formatted_biz_no ?? '',
                    $summary->member->corp_name ?? '',
                    $summary->bank_account_fee,
                    $summary->card_fee,
                    $summary->hometax_fee,
                    $summary->subscription_total,
                    $summary->tax_invoice_count,
                    $summary->tax_invoice_amount,
                    $summary->usage_total,
                    $summary->grand_total,
                ];
                if ($isHeadquarters || $allTenants) {
                    array_unshift($row, $summary->member->tenant_id ?? '', $summary->member->tenant->company_name ?? '');
                }
                fputcsv($file, $row);
            }

            // 합계
            $totalRow = ['', '합계', $total['bank_account_fee'], $total['card_fee'], $total['hometax_fee'], $total['subscription_total'], $total['tax_invoice_count'], $total['tax_invoice_amount'], $total['usage_total'], $total['grand_total']];
            if ($isHeadquarters || $allTenants) {
                array_unshift($totalRow, '', '');
            }
            fputcsv($file, $totalRow);

            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    // ========================================
    // 과금 정책 관리
    // ========================================

    /**
     * 과금 정책 목록 조회
     */
    public function pricingPolicies(Request $request): JsonResponse|Response
    {
        $policies = BarobillPricingPolicy::orderBy('sort_order')->get();

        if ($request->header('HX-Request')) {
            return response(
                view('barobill.billing.partials.pricing-policies-table', [
                    'policies' => $policies,
                ])->render(),
                200,
                ['Content-Type' => 'text/html']
            );
        }

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

    /**
     * 과금 정책 수정
     */
    public function updatePricingPolicy(Request $request, int $id): JsonResponse
    {
        $policy = BarobillPricingPolicy::find($id);
        if (! $policy) {
            return response()->json([
                'success' => false,
                'message' => '정책을 찾을 수 없습니다.',
            ], 404);
        }

        $validated = $request->validate([
            'name' => 'nullable|string|max:100',
            'description' => 'nullable|string|max:255',
            'free_quota' => 'nullable|integer|min:0',
            'free_quota_unit' => 'nullable|string|max:20',
            'additional_unit' => 'nullable|integer|min:1',
            'additional_unit_label' => 'nullable|string|max:20',
            'additional_price' => 'nullable|integer|min:0',
            'is_active' => 'nullable|boolean',
        ]);

        $policy->update($validated);

        return response()->json([
            'success' => true,
            'message' => '정책이 수정되었습니다.',
            'data' => $policy->fresh(),
        ]);
    }

    /**
     * 과금 정책 단일 조회
     */
    public function getPricingPolicy(int $id): JsonResponse
    {
        $policy = BarobillPricingPolicy::find($id);
        if (! $policy) {
            return response()->json([
                'success' => false,
                'message' => '정책을 찾을 수 없습니다.',
            ], 404);
        }

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