<?php

namespace App\Services;

use App\Models\NotificationSetting;
use App\Models\NotificationSettingGroup;
use App\Models\NotificationSettingGroupItem;
use App\Models\NotificationSettingGroupState;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class NotificationSettingService extends Service
{
    /**
     * 사용자의 알림 설정 조회
     */
    public function getSettings(): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $settings = NotificationSetting::where('tenant_id', $tenantId)
            ->forUser($userId)
            ->get()
            ->keyBy('notification_type');

        // 모든 알림 유형에 대한 설정 반환 (없으면 기본값)
        $result = [];
        foreach (NotificationSetting::getAllTypes() as $type) {
            if ($settings->has($type)) {
                $setting = $settings->get($type);
                $result[$type] = [
                    'notification_type' => $type,
                    'label' => NotificationSetting::getTypeLabels()[$type] ?? $type,
                    'push_enabled' => $setting->push_enabled,
                    'email_enabled' => $setting->email_enabled,
                    'sms_enabled' => $setting->sms_enabled,
                    'in_app_enabled' => $setting->in_app_enabled,
                    'kakao_enabled' => $setting->kakao_enabled,
                    'settings' => $setting->settings,
                ];
            } else {
                $defaults = NotificationSetting::getDefaultSettings($type);
                $result[$type] = array_merge([
                    'notification_type' => $type,
                    'label' => NotificationSetting::getTypeLabels()[$type] ?? $type,
                    'settings' => null,
                ], $defaults);
            }
        }

        return [
            'settings' => $result,
            'types' => NotificationSetting::getTypeLabels(),
            'channels' => NotificationSetting::getChannelLabels(),
        ];
    }

    /**
     * 특정 알림 유형 설정 업데이트
     */
    public function updateSetting(array $data): NotificationSetting
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $notificationType = $data['notification_type'];

        // 알림 유형 유효성 검증
        if (! in_array($notificationType, NotificationSetting::getAllTypes(), true)) {
            throw new \InvalidArgumentException(__('error.notification.invalid_type'));
        }

        return NotificationSetting::updateOrCreate(
            [
                'tenant_id' => $tenantId,
                'user_id' => $userId,
                'notification_type' => $notificationType,
            ],
            [
                'push_enabled' => $data['push_enabled'] ?? true,
                'email_enabled' => $data['email_enabled'] ?? false,
                'sms_enabled' => $data['sms_enabled'] ?? false,
                'in_app_enabled' => $data['in_app_enabled'] ?? true,
                'kakao_enabled' => $data['kakao_enabled'] ?? false,
                'settings' => $data['settings'] ?? null,
            ]
        );
    }

    /**
     * 알림 설정 일괄 업데이트
     */
    public function bulkUpdateSettings(array $settings): Collection
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($tenantId, $userId, $settings) {
            $updated = collect();

            foreach ($settings as $setting) {
                $notificationType = $setting['notification_type'];

                // 알림 유형 유효성 검증
                if (! in_array($notificationType, NotificationSetting::getAllTypes(), true)) {
                    continue;
                }

                $record = NotificationSetting::updateOrCreate(
                    [
                        'tenant_id' => $tenantId,
                        'user_id' => $userId,
                        'notification_type' => $notificationType,
                    ],
                    [
                        'push_enabled' => $setting['push_enabled'] ?? true,
                        'email_enabled' => $setting['email_enabled'] ?? false,
                        'sms_enabled' => $setting['sms_enabled'] ?? false,
                        'in_app_enabled' => $setting['in_app_enabled'] ?? true,
                        'kakao_enabled' => $setting['kakao_enabled'] ?? false,
                        'settings' => $setting['settings'] ?? null,
                    ]
                );

                $updated->push($record);
            }

            return $updated;
        });
    }

    /**
     * 기본 알림 설정 초기화
     */
    public function initializeDefaultSettings(): void
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        foreach (NotificationSetting::getAllTypes() as $type) {
            $defaults = NotificationSetting::getDefaultSettings($type);

            NotificationSetting::firstOrCreate(
                [
                    'tenant_id' => $tenantId,
                    'user_id' => $userId,
                    'notification_type' => $type,
                ],
                $defaults
            );
        }
    }

    /**
     * 특정 알림 유형에서 특정 채널이 활성화되어 있는지 확인
     */
    public function isChannelEnabled(int $userId, string $notificationType, string $channel): bool
    {
        $tenantId = $this->tenantId();

        $setting = NotificationSetting::where('tenant_id', $tenantId)
            ->forUser($userId)
            ->ofType($notificationType)
            ->first();

        if (! $setting) {
            // 기본 설정 반환
            $defaults = NotificationSetting::getDefaultSettings($notificationType);

            return match ($channel) {
                NotificationSetting::CHANNEL_PUSH => $defaults['push_enabled'],
                NotificationSetting::CHANNEL_EMAIL => $defaults['email_enabled'],
                NotificationSetting::CHANNEL_SMS => $defaults['sms_enabled'],
                NotificationSetting::CHANNEL_IN_APP => $defaults['in_app_enabled'],
                NotificationSetting::CHANNEL_KAKAO => $defaults['kakao_enabled'],
                default => false,
            };
        }

        return $setting->isChannelEnabled($channel);
    }

    // =========================================================================
    // 그룹 기반 알림 설정 (React 호환)
    // =========================================================================

    /**
     * 테넌트의 그룹 정의 초기화 (없으면 기본값 생성)
     */
    public function initializeGroupsIfNeeded(): void
    {
        $tenantId = $this->tenantId();

        $existingCount = NotificationSettingGroup::where('tenant_id', $tenantId)->count();
        if ($existingCount > 0) {
            return;
        }

        DB::transaction(function () use ($tenantId) {
            foreach (NotificationSettingGroup::DEFAULT_GROUPS as $groupData) {
                $group = NotificationSettingGroup::create([
                    'tenant_id' => $tenantId,
                    'code' => $groupData['code'],
                    'name' => $groupData['name'],
                    'sort_order' => $groupData['sort_order'],
                    'is_active' => true,
                ]);

                foreach ($groupData['items'] as $itemData) {
                    NotificationSettingGroupItem::create([
                        'group_id' => $group->id,
                        'notification_type' => $itemData['notification_type'],
                        'label' => $itemData['label'],
                        'sort_order' => $itemData['sort_order'],
                    ]);
                }
            }
        });
    }

    /**
     * 그룹 기반 알림 설정 조회 (React 구조로 반환)
     */
    public function getGroupedSettings(): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 그룹이 없으면 초기화
        $this->initializeGroupsIfNeeded();

        // 그룹 조회
        $groups = NotificationSettingGroup::where('tenant_id', $tenantId)
            ->active()
            ->ordered()
            ->with('items')
            ->get();

        // 그룹 상태 조회
        $groupStates = NotificationSettingGroupState::where('tenant_id', $tenantId)
            ->forUser($userId)
            ->get()
            ->keyBy('group_code');

        // 개별 설정 조회
        $settings = NotificationSetting::where('tenant_id', $tenantId)
            ->forUser($userId)
            ->get()
            ->keyBy('notification_type');

        // React 구조로 변환
        $result = [];
        foreach ($groups as $group) {
            $groupCode = $group->code;
            $groupEnabled = $groupStates->has($groupCode)
                ? $groupStates->get($groupCode)->enabled
                : true; // 기본값 true

            $groupData = ['enabled' => $groupEnabled];

            foreach ($group->items as $item) {
                $type = $item->notification_type;
                $camelKey = NotificationSettingGroup::toCamelCase($type);

                if ($settings->has($type)) {
                    $setting = $settings->get($type);
                    $groupData[$camelKey] = [
                        'enabled' => $setting->push_enabled,
                        'email' => $setting->email_enabled,
                    ];
                } else {
                    // 기본값
                    $groupData[$camelKey] = [
                        'enabled' => false,
                        'email' => false,
                    ];
                }
            }

            $result[$groupCode] = $groupData;
        }

        return $result;
    }

    /**
     * 그룹 기반 알림 설정 저장 (React 구조 입력)
     */
    public function updateGroupedSettings(array $data): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 그룹이 없으면 초기화
        $this->initializeGroupsIfNeeded();

        return DB::transaction(function () use ($tenantId, $userId, $data) {
            // 그룹 조회
            $groups = NotificationSettingGroup::where('tenant_id', $tenantId)
                ->active()
                ->with('items')
                ->get()
                ->keyBy('code');

            foreach ($data as $groupCode => $groupData) {
                if (! $groups->has($groupCode)) {
                    continue;
                }

                // 그룹 전체 활성화 상태 저장
                if (isset($groupData['enabled'])) {
                    NotificationSettingGroupState::updateOrCreate(
                        [
                            'tenant_id' => $tenantId,
                            'user_id' => $userId,
                            'group_code' => $groupCode,
                        ],
                        [
                            'enabled' => $groupData['enabled'],
                        ]
                    );
                }

                // 각 항목 설정 저장
                $group = $groups->get($groupCode);
                foreach ($group->items as $item) {
                    $type = $item->notification_type;
                    $camelKey = NotificationSettingGroup::toCamelCase($type);

                    if (isset($groupData[$camelKey])) {
                        $itemData = $groupData[$camelKey];
                        NotificationSetting::updateOrCreate(
                            [
                                'tenant_id' => $tenantId,
                                'user_id' => $userId,
                                'notification_type' => $type,
                            ],
                            [
                                'push_enabled' => $itemData['enabled'] ?? false,
                                'email_enabled' => $itemData['email'] ?? false,
                                'sms_enabled' => false,
                                'in_app_enabled' => $itemData['enabled'] ?? false,
                                'kakao_enabled' => false,
                            ]
                        );
                    }
                }
            }

            // 저장 후 결과 반환
            return $this->getGroupedSettings();
        });
    }
}
