<?php

declare(strict_types=1);

namespace App\Http\Controllers\Support;

use App\Http\Controllers\Helpers\ResponseHelper;
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
use App\Enums\UserTypes;
use App\Enums\UserActions;
use App\Models\Chapter;
use App\Models\ChapterMember;
use App\Models\User;
use App\Models\Market\UserInfo;
use App\Models\Market\CooperativeMember;
use App\Models\Market\Organization;
use App\Models\SystemSetting;
use App\Support\IslandGroupHelper;
use App\Support\SystemSettingsHelper;
use Hypervel\Http\Request;
use Hypervel\Support\Facades\Auth;
use Hypervel\Support\Facades\Hash;
use Hypervel\Support\Facades\Validator;
use Hypervel\Support\Str;

class ChapterController
{
    /** Child level mapping for chapter hierarchy. */
    private const CHILD_LEVELS = [
        'national'  => ['region'],
        'region'    => ['province'],
        'province'  => ['city', 'municipal'],
        'city'      => ['barangay'],
        'municipal' => ['barangay'],
        'barangay'  => [],
    ];

    private const OFFICER_ROLES = ['PRESIDENT', 'VICE_PRESIDENT', 'SECRETARY', 'TREASURER', 'AUDITOR', 'BOARD_MEMBER'];

    /** Big3 / Coordinator may act org-wide. */
    private function isAdminCaller($acctType): bool
    {
        return in_array($acctType, [
            UserTypes::ULTIMATE,
            UserTypes::SUPER_OPERATOR,
            UserTypes::OPERATOR,
            UserTypes::COORDINATOR,
        ], true);
    }

    /**
     * Resolve the caller's primary (highest) active chapter membership row,
     * joined with chapter columns. Returns null if none.
     */
    private function resolveCallerChapter(int $userId)
    {
        return ChapterMember::join('chapters', 'chapters.id', 'chapter_members.chapter_id')
            ->where('chapter_members.user_id', $userId)
            ->where('chapter_members.is_active', true)
            ->orderByRaw("FIELD(chapters.level,'national','region','province','city','municipal','barangay')")
            ->select(
                'chapter_members.*',
                'chapters.id as c_id',
                'chapters.name as c_name',
                'chapters.level as c_level',
                'chapters.hashkey as c_hashkey',
                'chapters.location_key as c_location_key',
                'chapters.cooperative_id as c_cooperative_id'
            )
            ->first();
    }

    private function chapterOfficers(int $chapterId): array
    {
        return ChapterMember::join('users', 'users.id', 'chapter_members.user_id')
            ->where('chapter_members.chapter_id', $chapterId)
            ->where('chapter_members.is_active', true)
            ->whereNotNull('chapter_members.role')
            ->where('chapter_members.role', '!=', 'MEMBER')
            ->select('users.name as name', 'users.fullname as fullname', 'chapter_members.role as role', 'chapter_members.position as position')
            ->get()
            ->map(fn ($r) => [
                'name'     => $r->fullname ?: $r->name,
                'role'     => $r->role,
                'position' => $r->position,
            ])
            ->values()
            ->all();
    }

    /**
     * Collect all chapter IDs in the subtree rooted at $rootId, scoped to $cooperativeId.
     */
    private function subtreeChapterIds(int $rootId, ?int $cooperativeId): array
    {
        $ids = [$rootId];
        $frontier = [$rootId];
        while (!empty($frontier)) {
            $q = Chapter::whereIn('parent_id', $frontier)->where('is_active', true);
            if ($cooperativeId !== null) {
                $q->where('cooperative_id', $cooperativeId);
            }
            $children = $q->pluck('id')->map(fn ($v) => (int) $v)->all();
            $children = array_values(array_diff($children, $ids));
            if (empty($children)) {
                break;
            }
            $ids = array_merge($ids, $children);
            $frontier = $children;
        }
        return $ids;
    }

    /**
     * Get hierarchy data for a given chapter level.
     * If chapter_id is null, returns national-level (all regions).
     * Otherwise returns children of the given chapter with member counts and leaders.
     */
    public function hierarchy(Request $request)
    {
        $chapterId = $request->input('chapter_id');

        if (!$chapterId) {
            // Return all regions under national
            $national = Chapter::where('level', 'national')->where('location_key', 'philippines')->first();
            if (!$national) {
                return response()->json(['chapters' => [], 'current' => null, 'breadcrumb' => []]);
            }
            $chapters = $national->children()
                ->where('is_active', true)
                ->withCount('activeMembers')
                ->with(['leaders.user'])
                ->get()
                ->map(fn($c) => $this->formatChapter($c))
                ->values();

            return response()->json([
                'chapters'   => $chapters,
                'current'    => null,
                'breadcrumb' => [],
            ]);
        }

        $current = Chapter::withCount('activeMembers')->with(['leaders.user'])->find($chapterId);
        if (!$current) {
            return ResponseHelper::returnError('Chapter not found', 404);
        }

        $chapters = $current->children()
            ->where('is_active', true)
            ->withCount('activeMembers')
            ->with(['leaders.user', 'children' => fn($q) => $q->where('is_active', true)])
            ->get()
            ->map(fn($c) => $this->formatChapter($c))
            ->values();

        return response()->json([
            'chapters'   => $chapters,
            'current'    => $this->formatChapter($current),
            'breadcrumb' => $this->buildBreadcrumb($current),
        ]);
    }

    /**
     * Get member dots for the map — returns lat/lng counts per chapter at requested level.
     */
    public function mapData(Request $request)
    {
        $level = $request->input('level', 'region');
        $parentId = $request->input('parent_id');

        $query = Chapter::where('level', $level)
            ->where('is_active', true)
            ->withCount('activeMembers');

        if ($parentId) {
            $query->where('parent_id', $parentId);
        }

        $chapters = $query->get()
            ->filter(fn($c) => $c->lat && $c->lng)
            ->map(function ($chapter) {
                return [
                    'id'    => $chapter->id,
                    'name'  => $chapter->name,
                    'level' => $chapter->level,
                    'lat'   => $chapter->lat,
                    'lng'   => $chapter->lng,
                    'count' => $chapter->active_members_count,
                ];
            })
            ->values();

        return response()->json(['chapters' => $chapters]);
    }

    /**
     * Get members for a specific chapter (paginated).
     */
    public function members(Request $request)
    {
        $chapterId = $request->input('chapter_id');
        if (!$chapterId) {
            return ResponseHelper::returnError('chapter_id required', 400);
        }

        $members = ChapterMember::with(['user', 'user.userInfo'])
            ->where('chapter_id', $chapterId)
            ->where('is_active', true)
            ->get()
            ->map(function ($cm) {
                $user = $cm->user;
                $info = $user?->userInfo;
                return [
                    'hashkey'    => $user?->hashkey,
                    'name'       => $user?->fullname ?? $user?->name,
                    'position'   => $cm->position,
                    'photo'      => $user?->photourl,
                    'region'     => $info?->region,
                    'province'   => $info?->province,
                    'city'       => $info?->city,
                    'barangay'   => $info?->barangay,
                    'is_manual'  => $cm->is_manual_override,
                ];
            });

        return response()->json(['members' => $members]);
    }

    /**
     * Assign or update a member's position / chapter assignment.
     */
    public function assignMember(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'user_hashkey' => 'required|string',
            'chapter_id'   => 'required|integer',
            'position'     => 'nullable|string',
            'is_manual'    => 'boolean',
        ]);

        if ($validator->fails()) {
            return ResponseHelper::returnError('Validation failed', 422, $validator->errors());
        }

        $user = User::where('hashkey', $request->user_hashkey)->first();
        if (!$user) {
            return ResponseHelper::returnError('User not found', 404);
        }

        $chapter = Chapter::find($request->chapter_id);
        if (!$chapter) {
            return ResponseHelper::returnError('Chapter not found', 404);
        }

        $existing = ChapterMember::where('user_id', $user->id)->where('chapter_id', $chapter->id)->first();

        if ($existing) {
            $existing->update([
                'position'           => $request->position,
                'is_manual_override' => $request->input('is_manual', true),
                'assigned_by'        => Auth::id(),
                'assigned_at'        => now(),
                'updated_by'         => Auth::id(),
            ]);
        } else {
            ChapterMember::create([
                'hashkey'            => (string) \Hypervel\Support\Str::uuid(),
                'user_id'            => $user->id,
                'chapter_id'         => $chapter->id,
                'position'           => $request->position,
                'is_manual_override' => $request->input('is_manual', true),
                'is_active'          => true,
                'assigned_by'        => Auth::id(),
                'assigned_at'        => now(),
                'created_by'         => Auth::id(),
            ]);
        }

        return response()->json(['success' => true]);
    }

    /**
     * Remove a member from a chapter assignment.
     */
    public function removeMember(Request $request)
    {
        $chapterMember = ChapterMember::where('hashkey', $request->input('hashkey'))->first();
        if (!$chapterMember) {
            return ResponseHelper::returnError('Member assignment not found', 404);
        }

        $chapterMember->update(['is_active' => false, 'updated_by' => Auth::id()]);
        return response()->json(['success' => true]);
    }

    /**
     * Trigger auto-assignment for all users based on their current addresses.
     */
    public function syncAllAutoAssignments()
    {
        $count = 0;
        UserInfo::whereNotNull('region')->chunk(100, function ($infos) use (&$count) {
            foreach ($infos as $info) {
                Chapter::autoAssignUser($info->user_id);
                $count++;
            }
        });
        
        return response()->json(['synced' => $count]);
    }

    /**
     * Get available positions from system settings.
     */
    public function positions()
    {
        $positions = SystemSetting::getValue('chapter_positions', json_encode(['Director', 'Coordinator', 'Officer', 'Secretary', 'Treasurer', 'Auditor', 'Member']));
        if (is_string($positions)) {
            $positions = json_decode($positions, true) ?? [];
        }
        return response()->json(['positions' => $positions]);
    }

    /**
     * Hierarchy scoped to members of the main organization, with a synthetic
     * "island_group" level above region (Luzon / Visayas / Mindanao).
     *
     * Inputs:
     *   - island: 'luzon'|'visayas'|'mindanao' to drill into an island group
     *   - chapter_id: real chapter id to drill into a region/province/city
     * If neither is provided, returns the 3 island groups with member counts.
     */
    public function orgHierarchy(Request $request)
    {
        $org = SystemSettingsHelper::mainOrganization();
        if (!$org) {
            return response()->json([
                'chapters' => [],
                'current' => null,
                'breadcrumb' => [],
                'error' => 'No main organization configured.',
            ]);
        }

        $orgUserIds = $this->orgUserIds((int) $org->id);
        $island = $request->input('island');
        $chapterId = $request->input('chapter_id');

        // Top level: 3 island groups
        if (!$chapterId && !$island) {
            $regionsByIsland = $this->regionIdsByIsland();
            $chapters = [];
            foreach (IslandGroupHelper::islands() as $isl) {
                $regionIds = $regionsByIsland[$isl] ?? [];
                $count = empty($regionIds) || empty($orgUserIds)
                    ? 0
                    : ChapterMember::whereIn('chapter_id', $regionIds)
                        ->whereIn('user_id', $orgUserIds)
                        ->where('is_active', true)
                        ->distinct('user_id')
                        ->count('user_id');
                $center = IslandGroupHelper::center($isl);
                $chapters[] = [
                    'id' => null,
                    'island' => $isl,
                    'hashkey' => 'island:' . $isl,
                    'name' => IslandGroupHelper::label($isl),
                    'level' => 'island_group',
                    'location_key' => $isl,
                    'lat' => $center['lat'],
                    'lng' => $center['lng'],
                    'member_count' => (int) $count,
                    'leaders' => [],
                    'has_children' => !empty($regionIds),
                ];
            }
            return response()->json([
                'chapters' => $chapters,
                'current' => null,
                'breadcrumb' => [],
            ]);
        }

        // Drilling into an island group: list its regions
        if ($island && !$chapterId) {
            $regionIds = $this->regionIdsByIsland()[$island] ?? [];
            if (empty($regionIds)) {
                return response()->json([
                    'chapters' => [],
                    'current' => $this->islandPseudoChapter($island),
                    'breadcrumb' => [],
                ]);
            }

            $chapters = Chapter::whereIn('id', $regionIds)
                ->where('is_active', true)
                ->with(['leaders.user', 'children' => fn($q) => $q->where('is_active', true)])
                ->get()
                ->map(fn($c) => $this->formatChapterScoped($c, $orgUserIds))
                ->values();

            return response()->json([
                'chapters' => $chapters,
                'current' => $this->islandPseudoChapter($island),
                'breadcrumb' => [],
            ]);
        }

        // Drilling into a real chapter (region/province/city) — return its children
        $current = Chapter::with(['leaders.user'])->find($chapterId);
        if (!$current) {
            return ResponseHelper::returnError('Chapter not found', 404);
        }

        $chapters = $current->children()
            ->where('is_active', true)
            ->with(['leaders.user', 'children' => fn($q) => $q->where('is_active', true)])
            ->get()
            ->map(fn($c) => $this->formatChapterScoped($c, $orgUserIds))
            ->values();

        return response()->json([
            'chapters' => $chapters,
            'current' => $this->formatChapterScoped($current, $orgUserIds),
            'breadcrumb' => $this->buildOrgBreadcrumb($current),
        ]);
    }

    /**
     * Map dots scoped to members of the main organization.
     * Levels: 'island_group' (3 dots), 'region', 'province', 'city', 'barangay'.
     */
    public function orgMapData(Request $request)
    {
        $org = SystemSettingsHelper::mainOrganization();
        if (!$org) {
            return response()->json(['chapters' => []]);
        }
        $orgUserIds = $this->orgUserIds((int) $org->id);

        $level = $request->input('level', 'island_group');
        $parentId = $request->input('parent_id');
        $island = $request->input('island');

        if ($level === 'island_group') {
            $regionsByIsland = $this->regionIdsByIsland();
            $dots = [];
            foreach (IslandGroupHelper::islands() as $isl) {
                $regionIds = $regionsByIsland[$isl] ?? [];
                $count = empty($regionIds) || empty($orgUserIds)
                    ? 0
                    : ChapterMember::whereIn('chapter_id', $regionIds)
                        ->whereIn('user_id', $orgUserIds)
                        ->where('is_active', true)
                        ->distinct('user_id')
                        ->count('user_id');
                $center = IslandGroupHelper::center($isl);
                $dots[] = [
                    'id' => null,
                    'island' => $isl,
                    'name' => IslandGroupHelper::label($isl),
                    'level' => 'island_group',
                    'lat' => $center['lat'],
                    'lng' => $center['lng'],
                    'count' => (int) $count,
                ];
            }
            return response()->json(['chapters' => $dots]);
        }

        $query = Chapter::where('level', $level)->where('is_active', true);

        if ($parentId) {
            $query->where('parent_id', $parentId);
        } elseif ($level === 'region' && $island) {
            $regionIds = $this->regionIdsByIsland()[$island] ?? [];
            if (empty($regionIds)) return response()->json(['chapters' => []]);
            $query->whereIn('id', $regionIds);
        }

        $chapters = $query->get()
            ->filter(fn($c) => $c->lat && $c->lng)
            ->map(function ($chapter) use ($orgUserIds) {
                return [
                    'id' => $chapter->id,
                    'name' => $chapter->name,
                    'level' => $chapter->level,
                    'lat' => $chapter->lat,
                    'lng' => $chapter->lng,
                    'count' => $this->scopedMemberCount($chapter->id, $orgUserIds),
                ];
            })
            ->values();

        return response()->json(['chapters' => $chapters]);
    }

    /**
     * Org chart for the caller's chapter (officers + direct children),
     * or — when a chapter_id is given — the officers of that specific chapter.
     */
    public function getOrgChart(Request $request)
    {
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }
        $acctType = $user->acct_type;

        // Drill request: officers of a specific child chapter.
        $requestedChapterId = $request->input('chapter_id');
        if ($requestedChapterId) {
            $chapter = Chapter::find($requestedChapterId);
            if (!$chapter) {
                return ResponseHelper::returnError('Chapter not found', 404);
            }
            return response()->json([
                'chapter'  => [
                    'id'       => $chapter->id,
                    'hashkey'  => $chapter->hashkey,
                    'name'     => $chapter->name,
                    'level'    => $chapter->level,
                ],
                'officers' => $this->chapterOfficers((int) $chapter->id),
            ]);
        }

        // Admin / coordinator: optional cooperative_id to view a coop's top chapter.
        if ($this->isAdminCaller($acctType)) {
            $cooperativeId = $request->input('cooperative_id');
            $rootQuery = Chapter::where('is_active', true)
                ->orderByRaw("FIELD(level,'national','region','province','city','municipal','barangay')");
            if ($cooperativeId) {
                $rootQuery->where('cooperative_id', $cooperativeId);
            }
            $root = $rootQuery->first();
            if (!$root) {
                return response()->json(['own_chapter' => null, 'children' => []]);
            }
            return response()->json([
                'own_chapter' => [
                    'id'           => $root->id,
                    'hashkey'      => $root->hashkey,
                    'name'         => $root->name,
                    'level'        => $root->level,
                    'location_key' => $root->location_key,
                    'officers'     => $this->chapterOfficers((int) $root->id),
                ],
                'children' => $this->childChapterRows((int) $root->id, $root->cooperative_id),
            ]);
        }

        $cm = $this->resolveCallerChapter((int) $user->id);
        if (!$cm) {
            return response()->json(['own_chapter' => null, 'children' => []]);
        }

        $ownChapter = [
            'id'           => (int) $cm->c_id,
            'hashkey'      => $cm->c_hashkey,
            'name'         => $cm->c_name,
            'level'        => $cm->c_level,
            'location_key' => $cm->c_location_key,
            'officers'     => $this->chapterOfficers((int) $cm->c_id),
        ];

        // COOP_MEMBER: own chapter + officers only, no children/member lists.
        if ($acctType === UserTypes::COOP_MEMBER) {
            return response()->json(['own_chapter' => $ownChapter, 'children' => []]);
        }

        return response()->json([
            'own_chapter' => $ownChapter,
            'children'    => $this->childChapterRows((int) $cm->c_id, $cm->c_cooperative_id),
        ]);
    }

    /**
     * Direct child chapters with active member counts (officers collapsed/empty).
     */
    private function childChapterRows(int $parentId, $cooperativeId): array
    {
        $query = Chapter::where('parent_id', $parentId)->where('is_active', true);
        if ($cooperativeId !== null) {
            $query->where('cooperative_id', $cooperativeId);
        }
        return $query->withCount('activeMembers')->get()->map(fn ($c) => [
            'id'           => (int) $c->id,
            'hashkey'      => $c->hashkey,
            'name'         => $c->name,
            'level'        => $c->level,
            'member_count' => (int) $c->active_members_count,
            'officers'     => [],
        ])->values()->all();
    }

    /**
     * Caller's own chapter + direct children + cooperative + eligible (non-officer) members.
     */
    public function getOfficerScope(Request $request)
    {
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }

        $cm = $this->resolveCallerChapter((int) $user->id);
        if (!$cm) {
            return response()->json([
                'own_chapter'      => null,
                'child_chapters'   => [],
                'cooperative'      => null,
                'eligible_members' => [],
            ]);
        }

        $coop = $cm->c_cooperative_id
            ? Organization::where('id', $cm->c_cooperative_id)->first(['hashkey', 'name'])
            : null;

        $childChapters = Chapter::where('parent_id', $cm->c_id)
            ->where('is_active', true)
            ->when($cm->c_cooperative_id !== null, fn ($q) => $q->where('cooperative_id', $cm->c_cooperative_id))
            ->withCount('activeMembers')
            ->get()
            ->map(fn ($c) => [
                'id'                   => (int) $c->id,
                'hashkey'              => $c->hashkey,
                'name'                 => $c->name,
                'level'                => $c->level,
                'active_members_count' => (int) $c->active_members_count,
            ])->values()->all();

        $eligible = ChapterMember::join('users', 'users.id', 'chapter_members.user_id')
            ->where('chapter_members.chapter_id', $cm->c_id)
            ->where('chapter_members.is_active', true)
            ->where(function ($q) {
                $q->whereNull('chapter_members.role')->orWhere('chapter_members.role', 'MEMBER');
            })
            ->select('users.hashkey as user_hashkey', 'users.name as name', 'users.fullname as fullname', 'chapter_members.role as role')
            ->get()
            ->map(fn ($r) => [
                'user_hashkey' => $r->user_hashkey,
                'name'         => $r->fullname ?: $r->name,
                'role'         => $r->role,
            ])->values()->all();

        return response()->json([
            'own_chapter' => [
                'id'      => (int) $cm->c_id,
                'hashkey' => $cm->c_hashkey,
                'name'    => $cm->c_name,
                'level'   => $cm->c_level,
            ],
            'child_chapters'   => $childChapters,
            'cooperative'      => $coop ? ['hashkey' => $coop->hashkey, 'name' => $coop->name] : null,
            'eligible_members' => $eligible,
        ]);
    }

    /**
     * Name-only member search across the caller's chapter subtree.
     * Returns ONLY name, role, chapter_name — no contact/identifying fields.
     */
    public function memberSearch(Request $request)
    {
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }
        if (!UserPermissions::isActionPermitted($user->acct_type, UserActions::ManageChapterMembers)) {
            return ResponseHelper::returnUnauthorized();
        }

        $validator = Validator::make($request->all(), [
            'query' => 'required|string|min:2',
        ]);
        if ($validator->fails()) {
            return ResponseHelper::returnError('Validation failed', 422, $validator->errors());
        }

        $query = trim((string) $request->input('query'));

        $scopeIds = [];
        if ($this->isAdminCaller($user->acct_type)) {
            // Admins: search all active chapters.
            $scopeIds = Chapter::where('is_active', true)->pluck('id')->map(fn ($v) => (int) $v)->all();
        } else {
            $cm = $this->resolveCallerChapter((int) $user->id);
            if (!$cm) {
                return response()->json(['members' => []]);
            }
            $scopeIds = $this->subtreeChapterIds((int) $cm->c_id, $cm->c_cooperative_id);
        }

        if (empty($scopeIds)) {
            return response()->json(['members' => []]);
        }

        $members = User::join('chapter_members', 'users.id', 'chapter_members.user_id')
            ->join('chapters', 'chapters.id', 'chapter_members.chapter_id')
            ->whereIn('chapter_members.chapter_id', $scopeIds)
            ->where('chapter_members.is_active', true)
            ->where('users.name', 'LIKE', "%{$query}%")
            ->select('users.name as name', 'chapter_members.role as role', 'chapters.name as chapter_name')
            ->distinct()
            ->limit(30)
            ->get()
            ->map(fn ($r) => [
                'name'         => $r->name,
                'role'         => $r->role,
                'chapter_name' => $r->chapter_name,
            ])->values()->all();

        return response()->json(['members' => $members]);
    }

    /**
     * Move an eligible member of the caller's chapter to a direct child chapter as an officer.
     */
    public function assignOfficer(Request $request)
    {
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }
        if (!UserPermissions::isActionPermitted($user->acct_type, UserActions::AssignChapterOfficer)) {
            return ResponseHelper::returnUnauthorized();
        }

        $validator = Validator::make($request->all(), [
            'member_user_hashkey' => 'required|string',
            'child_chapter_id'    => 'required|integer',
            'role'                => 'required|string|in:' . implode(',', self::OFFICER_ROLES),
        ]);
        if ($validator->fails()) {
            return ResponseHelper::returnError('Validation failed', 422, $validator->errors());
        }

        $cm = $this->resolveCallerChapter((int) $user->id);
        if (!$cm && !$this->isAdminCaller($user->acct_type)) {
            return ResponseHelper::returnError('You are not assigned to a chapter.', 422);
        }

        $member = User::where('hashkey', $request->input('member_user_hashkey'))->first();
        if (!$member) {
            return ResponseHelper::returnError('Member not found', 404);
        }

        $childChapter = Chapter::find($request->input('child_chapter_id'));
        if (!$childChapter) {
            return ResponseHelper::returnError('Child chapter not found', 404);
        }

        // Eligibility B — child must be a direct child of caller's chapter (admins exempt).
        if (!$this->isAdminCaller($user->acct_type)) {
            if ((int) $childChapter->parent_id !== (int) $cm->c_id
                || (int) $childChapter->cooperative_id !== (int) $cm->c_cooperative_id) {
                return ResponseHelper::returnError('Selected chapter is not a direct sub-chapter of your chapter.', 422);
            }
        }

        // Eligibility A — member must be an active non-officer in the caller's chapter.
        $parentChapterId = $this->isAdminCaller($user->acct_type) ? (int) $childChapter->parent_id : (int) $cm->c_id;
        $parentMembership = ChapterMember::where('user_id', $member->id)
            ->where('chapter_id', $parentChapterId)
            ->where('is_active', true)
            ->first();
        if (!$parentMembership) {
            return ResponseHelper::returnError('Member is not part of the parent chapter.', 422);
        }
        if (!empty($parentMembership->role) && $parentMembership->role !== 'MEMBER') {
            return ResponseHelper::returnError('Member is already an officer.', 422);
        }

        $role = $request->input('role');

        // 1. Remove existing parent-chapter membership (MOVE, not copy).
        $parentMembership->update(['is_active' => false, 'updated_by' => Auth::id()]);

        // 2. Upsert child-chapter officer membership.
        $existingChild = ChapterMember::where('user_id', $member->id)
            ->where('chapter_id', $childChapter->id)
            ->first();
        if ($existingChild) {
            $existingChild->update([
                'role'               => $role,
                'position'           => $role,
                'is_manual_override' => true,
                'assigned_by'        => Auth::id(),
                'assigned_at'        => now(),
                'is_active'          => true,
                'updated_by'         => Auth::id(),
            ]);
        } else {
            ChapterMember::create([
                'hashkey'            => Str::random(64),
                'user_id'            => $member->id,
                'chapter_id'         => $childChapter->id,
                'role'               => $role,
                'position'           => $role,
                'is_manual_override' => true,
                'assigned_by'        => Auth::id(),
                'assigned_at'        => now(),
                'is_active'          => true,
                'created_by'         => Auth::id(),
                'updated_by'         => Auth::id(),
            ]);
        }

        // 3. Upgrade acct_type if currently a plain coop member.
        if ($member->acct_type === UserTypes::COOP_MEMBER) {
            $member->acct_type = UserTypes::COOP_OFFICER;
            $member->save();
        }

        return response()->json([
            'success' => true,
            'message' => "Assigned {$member->name} as {$role} to {$childChapter->name}.",
        ]);
    }

    /**
     * Create a chapter one level below the caller's chapter, scoped to its cooperative.
     */
    public function createChapter(Request $request)
    {
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }
        if (!UserPermissions::isActionPermitted($user->acct_type, UserActions::ManageChapterMembers)) {
            return ResponseHelper::returnUnauthorized();
        }

        $validator = Validator::make($request->all(), [
            'name'         => 'required|string|max:255',
            'location_key' => 'required|string|max:255',
            'lat'          => 'nullable|numeric',
            'lng'          => 'nullable|numeric',
        ]);
        if ($validator->fails()) {
            return ResponseHelper::returnError('Validation failed', 422, $validator->errors());
        }

        $cm = $this->resolveCallerChapter((int) $user->id);
        if (!$cm) {
            return ResponseHelper::returnError('You are not assigned to a chapter.', 422);
        }

        $childLevels = self::CHILD_LEVELS[$cm->c_level] ?? [];
        if (empty($childLevels)) {
            return ResponseHelper::returnError('Cannot create sub-chapters at barangay level.', 422);
        }
        $childLevel = $childLevels[0];

        $chapter = Chapter::create([
            'hashkey'        => \Ramsey\Uuid\Uuid::uuid4()->toString(),
            'name'           => trim((string) $request->input('name')),
            'level'          => $childLevel,
            'parent_id'      => (int) $cm->c_id,
            'cooperative_id' => $cm->c_cooperative_id,
            'location_key'   => strtolower(trim((string) $request->input('location_key'))),
            'lat'            => $request->input('lat'),
            'lng'            => $request->input('lng'),
            'is_active'      => true,
            'created_by'     => Auth::id(),
            'updated_by'     => Auth::id(),
        ]);

        return response()->json([
            'success' => true,
            'chapter' => [
                'hashkey' => $chapter->hashkey,
                'name'    => $chapter->name,
                'level'   => $chapter->level,
            ],
        ]);
    }

    /**
     * Public: get minimal chapter + cooperative info for a registration link.
     */
    public function publicGetChapter(Request $request, string $hkey)
    {
        $chapter = Chapter::where('hashkey', $hkey)->where('is_active', true)->first();
        if (!$chapter) {
            return response()->json(['success' => false, 'message' => 'Chapter not found'], 404);
        }
        $coop = $chapter->cooperative_id
            ? Organization::where('id', $chapter->cooperative_id)->first(['name'])
            : null;

        return response()->json([
            'success'     => true,
            'chapter'     => ['name' => $chapter->name, 'level' => $chapter->level],
            'cooperative' => ['name' => $coop?->name],
        ]);
    }

    /**
     * Public: register a new coop member directly into a chapter via a shared link.
     */
    public function publicRegisterToChapter(Request $request)
    {
        $hkey = $request->input('chapter_hash');
        if (!$hkey) {
            return ResponseHelper::returnIncorrectDetails();
        }

        $chapter = Chapter::where('hashkey', $hkey)->where('is_active', true)->first();
        if (!$chapter) {
            return response()->json(['success' => false, 'message' => 'Chapter not found'], 404);
        }

        $cooperative = $chapter->cooperative_id
            ? Organization::where('id', $chapter->cooperative_id)->where('type', 'COOPERATIVE')->first()
            : null;

        $validator = Validator::make($request->all(), [
            'name'          => 'required|string|max:255',
            'username'      => 'required|string|max:255|unique:users,username',
            'mobile_number' => ['required', 'string', 'max:20', 'unique:users,mobile_number', 'regex:/^(09|\+639)\d{9}$/'],
            'password'      => 'required|string|min:6',
        ]);
        if ($validator->fails()) {
            return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
        }
        $validated = $validator->validated();

        $parentUser = User::where('id', $chapter->created_by)->first()
            ?? User::where('acct_type', UserTypes::COORDINATOR->value)->first()
            ?? User::orderBy('id')->first();
        if (!$parentUser) {
            return response()->json(['success' => false, 'message' => 'No valid parent user found'], 500);
        }

        $user = new User();
        $user->username      = $validated['username'];
        $user->name          = $validated['name'];
        $user->mobile_number = $validated['mobile_number'];
        $user->password      = Hash::make($validated['password']);
        $user->parentuid     = $parentUser->id;
        $user->acct_type     = UserTypes::COOP_MEMBER;
        $user->active        = true;
        if ($cooperative) {
            $settings = $user->settings ?? [];
            if (!is_array($settings)) {
                $settings = [];
            }
            $settings['cooperatives'] = [$cooperative->hashkey];
            $user->settings = $settings;
        }
        $user->save();

        // Link to cooperative.
        if ($cooperative) {
            CooperativeMember::create([
                'hashkey'         => Str::random(64),
                'organization_id' => $cooperative->id,
                'user_id'         => $user->id,
                'is_active'       => true,
                'created_by'      => $user->id,
                'updated_by'      => $user->id,
            ]);
        }

        // Link to chapter.
        ChapterMember::create([
            'hashkey'            => Str::random(64),
            'user_id'            => $user->id,
            'chapter_id'         => $chapter->id,
            'is_manual_override' => false,
            'is_active'          => true,
            'created_by'         => $user->id,
            'updated_by'         => $user->id,
        ]);

        return response()->json([
            'success'      => true,
            'user_hashkey' => $user->hashkey,
            'message'      => 'Account created. You may now log in.',
        ], 201);
    }

    // --- Private helpers ---

    private function formatChapter(Chapter $chapter): array
    {
        $memberCount = $chapter->active_members_count ?? $chapter->activeMembers()->count();
        
        $leaders = $chapter->leaders->map(fn($cm) => [
            'name'     => $cm->user?->fullname ?? $cm->user?->name,
            'position' => $cm->position,
            'photo'    => $cm->user?->photourl,
            'hashkey'  => $cm->user?->hashkey,
        ])->values()->toArray();

        // Check if children already loaded, otherwise count
        $hasChildren = $chapter->relationLoaded('children') 
            ? $chapter->children->isNotEmpty() 
            : $chapter->children()->where('is_active', true)->exists();

        return [
            'id'           => $chapter->id,
            'hashkey'      => $chapter->hashkey,
            'name'         => $chapter->name,
            'level'        => $chapter->level,
            'location_key' => $chapter->location_key,
            'lat'          => $chapter->lat,
            'lng'          => $chapter->lng,
            'member_count' => (int) $memberCount,
            'leaders'      => $leaders,
            'has_children' => (bool) $hasChildren,
        ];
    }


    /**
     * IDs of users who are active CooperativeMember rows of the given organization.
     * Returns [] if none — callers should treat that as "no scoped members".
     */
    private function orgUserIds(int $organizationId): array
    {
        return CooperativeMember::where('organization_id', $organizationId)
            ->pluck('user_id')
            ->filter()
            ->unique()
            ->values()
            ->all();
    }

    private function scopedMemberCount(int $chapterId, array $orgUserIds): int
    {
        if (empty($orgUserIds)) return 0;
        return (int) ChapterMember::where('chapter_id', $chapterId)
            ->where('is_active', true)
            ->whereIn('user_id', $orgUserIds)
            ->count();
    }

    /**
     * Build a map of island_group → [region chapter ids] using IslandGroupHelper.
     */
    private function regionIdsByIsland(): array
    {
        $map = [
            IslandGroupHelper::LUZON => [],
            IslandGroupHelper::VISAYAS => [],
            IslandGroupHelper::MINDANAO => [],
        ];
        $regions = Chapter::where('level', 'region')->where('is_active', true)->get(['id', 'name', 'location_key']);
        foreach ($regions as $r) {
            $island = IslandGroupHelper::fromRegion($r->location_key)
                ?? IslandGroupHelper::fromRegion($r->name);
            if ($island && isset($map[$island])) {
                $map[$island][] = (int) $r->id;
            }
        }
        return $map;
    }

    private function islandPseudoChapter(string $island): array
    {
        $center = IslandGroupHelper::center($island);
        return [
            'id' => null,
            'island' => $island,
            'hashkey' => 'island:' . $island,
            'name' => IslandGroupHelper::label($island),
            'level' => 'island_group',
            'location_key' => $island,
            'lat' => $center['lat'],
            'lng' => $center['lng'],
            'member_count' => 0,
            'leaders' => [],
            'has_children' => true,
        ];
    }

    /**
     * Same as formatChapter but member_count is scoped to org user ids.
     * Leaders are filtered to those whose user is in the org.
     */
    private function formatChapterScoped(Chapter $chapter, array $orgUserIds): array
    {
        $memberCount = $this->scopedMemberCount((int) $chapter->id, $orgUserIds);

        $leaders = $chapter->leaders
            ->filter(fn($cm) => empty($orgUserIds) ? false : in_array((int) $cm->user_id, $orgUserIds, true))
            ->map(fn($cm) => [
                'name' => $cm->user?->fullname ?? $cm->user?->name,
                'position' => $cm->position,
                'photo' => $cm->user?->photourl,
                'hashkey' => $cm->user?->hashkey,
            ])->values()->toArray();

        $hasChildren = $chapter->relationLoaded('children')
            ? $chapter->children->isNotEmpty()
            : $chapter->children()->where('is_active', true)->exists();

        return [
            'id' => $chapter->id,
            'hashkey' => $chapter->hashkey,
            'name' => $chapter->name,
            'level' => $chapter->level,
            'location_key' => $chapter->location_key,
            'lat' => $chapter->lat,
            'lng' => $chapter->lng,
            'member_count' => (int) $memberCount,
            'leaders' => $leaders,
            'has_children' => (bool) $hasChildren,
        ];
    }

    /**
     * Breadcrumb walking up to the region, then prepending the island group.
     */
    private function buildOrgBreadcrumb(Chapter $chapter): array
    {
        $crumbs = [];
        $current = $chapter;
        while ($current->parent_id) {
            $current = $current->parent;
            if (!$current) break;
            if ($current->level === 'national') break;
            array_unshift($crumbs, ['id' => $current->id, 'name' => $current->name, 'level' => $current->level]);
        }
        // Determine island from the topmost region in the trail (or the chapter itself).
        $regionRow = collect($crumbs)->first(fn($c) => $c['level'] === 'region');
        $regionName = $regionRow['name'] ?? ($chapter->level === 'region' ? $chapter->name : null);
        $island = IslandGroupHelper::fromRegion($regionName);
        if ($island) {
            array_unshift($crumbs, [
                'id' => null,
                'island' => $island,
                'name' => IslandGroupHelper::label($island),
                'level' => 'island_group',
            ]);
        }
        return $crumbs;
    }

    private function buildBreadcrumb(Chapter $chapter): array
    {
        $breadcrumb = [];
        $current = $chapter;
        while ($current->parent_id) {
            $current = $current->parent;
            if (!$current) break;
            array_unshift($breadcrumb, ['id' => $current->id, 'name' => $current->name, 'level' => $current->level]);
        }
        return $breadcrumb;
    }
}
