<?php

namespace App\Http\Controllers;

use App\Models\Family;
use App\Models\Person;
use App\Models\Relationship;
use Illuminate\Http\Request;

class FamilyTreeController extends Controller
{
    public function show(Request $request, Family $family)
    {
        $this->authorizeMember($request, $family);

        // Determine the centered person for the tree
        $centerId = (int) $request->integer('person_id', 0);
        if ($centerId > 0) {
            $belongs = $family->members()->where('people.id', $centerId)->exists();
            if (! $belongs) {
                $centerId = 0;
            }
        }

        if ($centerId === 0) {
            if (! empty($family->head_person_id) && $family->members()->where('people.id', $family->head_person_id)->exists()) {
                $centerId = (int) $family->head_person_id;
            } else {
                $user = $request->user();
                $p = $user?->person;
                if ($p && $family->members()->where('people.id', $p->id)->exists()) {
                    $centerId = (int) $p->id;
                } else {
                    $centerId = (int) ($family->members()->value('people.id') ?? 0);
                }
            }
        }

        $center = $centerId ? Person::find($centerId) : null;

        // If no members/center found, render an empty state
        if (! $center) {
            return view('families.tree', [
                'family' => $family,
                'center' => null,
                'parents' => collect(),
                'spouses' => collect(),
                'children' => collect(),
                'siblings' => collect(),
                'members' => $family->members()->select('people.id','first_name','last_name')->get()->map(fn($p)=>[
                    'id'=>$p->id,
                    'name'=>trim(($p->first_name??'').' '.($p->last_name??'')) ?: 'Member',
                ]),
            ]);
        }

        // Build immediate relatives using the symmetric relationship lookup within this family
        $parentIds = collect()
            ->merge(Relationship::where('family_id', $family->id)->where('type','parent')->where('related_person_id', $centerId)->pluck('person_id'))
            ->merge(Relationship::where('family_id', $family->id)->where('type','child')->where('person_id', $centerId)->pluck('related_person_id'))
            ->unique()->values();

        $spouseIds = collect()
            ->merge(Relationship::where('family_id', $family->id)->where('type','spouse')->where('person_id', $centerId)->pluck('related_person_id'))
            ->merge(Relationship::where('family_id', $family->id)->where('type','spouse')->where('related_person_id', $centerId)->pluck('person_id'))
            ->unique()->values();

        $childIds = collect()
            ->merge(Relationship::where('family_id', $family->id)->where('type','parent')->where('person_id', $centerId)->pluck('related_person_id'))
            ->merge(Relationship::where('family_id', $family->id)->where('type','child')->where('related_person_id', $centerId)->pluck('person_id'))
            ->unique()->values();

        $siblingIds = collect()
            ->merge(Relationship::where('family_id', $family->id)->where('type','sibling')->where('person_id', $centerId)->pluck('related_person_id'))
            ->merge(Relationship::where('family_id', $family->id)->where('type','sibling')->where('related_person_id', $centerId)->pluck('person_id'));

        // Add siblings inferred from shared parents
        foreach ($parentIds as $pid) {
            $siblingIds = $siblingIds->merge(
                Relationship::where('family_id', $family->id)->where('type','parent')->where('person_id', $pid)->pluck('related_person_id')
            );
        }
        $siblingIds = $siblingIds->filter(fn($id)=> (int)$id !== (int)$centerId)->unique()->values();

        // Fetch person records
        $parents = $parentIds->isNotEmpty() ? Person::whereIn('id', $parentIds)->get() : collect();
        $spouses = $spouseIds->isNotEmpty() ? Person::whereIn('id', $spouseIds)->get() : collect();
        $children = $childIds->isNotEmpty() ? Person::whereIn('id', $childIds)->get() : collect();
        $siblings = $siblingIds->isNotEmpty() ? Person::whereIn('id', $siblingIds)->get() : collect();

        $members = $family->members()->select('people.id','first_name','last_name','photo_url')->orderBy('first_name')->get()->map(fn($p)=>[
            'id'=>$p->id,
            'name'=>trim(($p->first_name??'').' '.($p->last_name??'')) ?: 'Member',
        ]);

        // Phase 2: Multi-level expansion (ancestors/descendants)
        $depth = max(1, min((int) $request->integer('depth', 2), 5));

        $parentsOf = function (int $pid) use ($family) {
            return collect()
                ->merge(Relationship::where('family_id', $family->id)->where('type','parent')->where('related_person_id', $pid)->pluck('person_id'))
                ->merge(Relationship::where('family_id', $family->id)->where('type','child')->where('person_id', $pid)->pluck('related_person_id'))
                ->unique()->values();
        };

        $childrenOf = function (int $pid) use ($family) {
            return collect()
                ->merge(Relationship::where('family_id', $family->id)->where('type','parent')->where('person_id', $pid)->pluck('related_person_id'))
                ->merge(Relationship::where('family_id', $family->id)->where('type','child')->where('related_person_id', $pid)->pluck('person_id'))
                ->unique()->values();
        };

        // Build ancestor levels (upwards)
        $ancestorIdLevels = [];
        $prev = $center ? collect([$center->id]) : collect();
        for ($i = 0; $i < $depth && $prev->isNotEmpty(); $i++) {
            $next = collect();
            foreach ($prev as $pid) { $next = $next->merge($parentsOf((int)$pid)); }
            $next = $next->unique()->values();
            if ($next->isEmpty()) { break; }
            $ancestorIdLevels[] = $next;
            $prev = $next;
        }
        $ancestors = array_map(function($ids){ return $ids->isNotEmpty() ? Person::whereIn('id', $ids)->get() : collect(); }, $ancestorIdLevels);

        // Build descendant levels (downwards)
        $descendantIdLevels = [];
        $prev = $center ? collect([$center->id]) : collect();
        for ($i = 0; $i < $depth && $prev->isNotEmpty(); $i++) {
            $next = collect();
            foreach ($prev as $pid) { $next = $next->merge($childrenOf((int)$pid)); }
            $next = $next->unique()->values();
            if ($next->isEmpty()) { break; }
            $descendantIdLevels[] = $next;
            $prev = $next;
        }
        $descendants = array_map(function($ids){ return $ids->isNotEmpty() ? Person::whereIn('id', $ids)->get() : collect(); }, $descendantIdLevels);

        // Determine if current user can manage relationships (owner or explicit permission)
        $user = $request->user();
        $isOwner = $user && (((int) $family->created_by === (int) $user->id) || $family->members()
            ->wherePivot('role', 'owner')
            ->where('people.user_id', $user->id)
            ->exists());
        $canManage = $user && ($user->can('relationships.manage') || $isOwner);

        return view('families.tree', [
            'family' => $family,
            'center' => $center,
            'parents' => $parents,
            'spouses' => $spouses,
            'children' => $children,
            'siblings' => $siblings,
            'members' => $members,
            'ancestors' => $ancestors,
            'descendants' => $descendants,
            'depth' => $depth,
            'canManage' => $canManage,
        ]);
    }

    private function authorizeMember(Request $request, Family $family): void
    {
        $user = $request->user();
        $isOwner = $user && (int) $family->created_by === (int) $user->id;
        $isMember = $user && $family->members()->where('people.user_id', $user->id)->exists();
        abort_unless($isOwner || $isMember, 403);
    }
}
