<?php

namespace App\Services\Families;

use App\Models\Family;
use App\Models\FamilyGuardian;
use App\Models\FamilyStudent;
use App\Models\Student;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;

class FamilyMutationService
{
    public function bootstrapFamilies(): array
    {
        $this->ensureTablesExist(['families', 'family_students', 'family_guardians']);

        return DB::transaction(function () {
            $primaryParents = DB::table('students')
                ->select('parent_id')
                ->whereNotNull('parent_id')
                ->distinct()
                ->get()
                ->map(fn ($r) => (array) $r)
                ->all();

            $created = 0;
            $linkedStudents = 0;
            $linkedGuardians = 0;

            foreach ($primaryParents as $row) {
                $primaryUserId = (int) ($row['parent_id'] ?? 0);
                if ($primaryUserId <= 0) {
                    continue;
                }

                $familyId = $this->ensureFamilyForPrimaryParent($primaryUserId, $created);

                $students = DB::table('students')
                    ->select('id')
                    ->where('parent_id', $primaryUserId)
                    ->get()
                    ->map(fn ($r) => (array) $r)
                    ->all();

                foreach ($students as $s) {
                    $linkedStudents += $this->attachStudentToFamily((int) ($s['id'] ?? 0), $familyId);
                }

                $linkedGuardians += $this->attachGuardianUser($familyId, $primaryUserId, 'primary', true, 1, 0);
            }

            return [
                'families_created' => $created,
                'students_linked' => $linkedStudents,
                'guardians_linked' => $linkedGuardians,
            ];
        });
    }

    public function attachSecondByUser(int $studentId, int $userId, string $relation = 'secondary'): array
    {
        if ($studentId <= 0 || $userId <= 0) {
            return ['ok' => false, 'message' => 'student_id and user_id required'];
        }

        $familyId = $this->familyIdFromStudentPrimary($studentId);
        if (!$familyId) {
            return ['ok' => false, 'message' => 'No primary family found for this student'];
        }

        $rows = $this->attachGuardianUser($familyId, $userId, $relation, false, 1, 0);

        return ['ok' => true, 'attached' => $rows, 'family_id' => $familyId];
    }

    public function attachSecondByEmail(int $studentId, string $email, ?string $firstname, ?string $lastname, string $relation = 'secondary'): array
    {
        if ($studentId <= 0 || $email === '') {
            return ['ok' => false, 'message' => 'student_id and email required'];
        }

        $familyId = $this->familyIdFromStudentPrimary($studentId);
        if (!$familyId) {
            return ['ok' => false, 'message' => 'No primary family found for this student'];
        }

        return DB::transaction(function () use ($email, $firstname, $lastname, $relation, $familyId) {
            $user = User::query()->where('email', $email)->first();
            if (!$user) {
                $user = User::query()->create([
                    'firstname' => (string) ($firstname ?? ''),
                    'lastname' => (string) ($lastname ?? ''),
                    'email' => $email,
                    'status' => 'Active',
                    'user_type' => 'secondary',
                    'cellphone' => '',
                    'address_street' => '',
                    'city' => '',
                    'state' => '',
                    'zip' => '',
                    'accept_school_policy' => 1,
                    'password' => bcrypt('temporary'),
                    'semester' => '',
                ]);
            }

            $rows = $this->attachGuardianUser($familyId, (int) $user->id, $relation, false, 1, 0);

            return [
                'ok' => true,
                'attached' => $rows,
                'family_id' => $familyId,
                'user_id' => (int) $user->id,
            ];
        });
    }

    public function setPrimaryHome(int $familyId, int $studentId, bool $isPrimaryHome): void
    {
        FamilyStudent::query()
            ->where('family_id', $familyId)
            ->where('student_id', $studentId)
            ->update(['is_primary_home' => $isPrimaryHome ? 1 : 0]);
    }

    public function setGuardianFlags(int $familyId, int $userId, array $flags): void
    {
        $data = [];
        foreach (['receive_emails', 'is_primary', 'receive_sms', 'relation'] as $key) {
            if (array_key_exists($key, $flags)) {
                $value = $flags[$key];
                $data[$key] = in_array($key, ['receive_emails', 'is_primary', 'receive_sms'], true)
                    ? (int) $value
                    : (string) $value;
            }
        }
        if (empty($data)) {
            return;
        }

        FamilyGuardian::query()
            ->where('family_id', $familyId)
            ->where('user_id', $userId)
            ->update($data);
    }

    public function unlinkGuardian(int $familyId, int $userId): void
    {
        FamilyGuardian::query()
            ->where('family_id', $familyId)
            ->where('user_id', $userId)
            ->delete();
    }

    public function unlinkStudent(int $familyId, int $studentId): void
    {
        FamilyStudent::query()
            ->where('family_id', $familyId)
            ->where('student_id', $studentId)
            ->delete();
    }

    public function importSecondParentsFromLegacy(): array
    {
        $legacyTable = 'parents';
        $this->ensureTablesExist(['families', 'family_students', 'family_guardians']);
        if (!Schema::hasTable($legacyTable)) {
            return ['ok' => false, 'message' => "Legacy table '{$legacyTable}' not found"];
        }

        $rows = DB::table($legacyTable)
            ->selectRaw('firstparent_id AS first_id, secondparent_id AS second_id, secondparent_email AS email, secondparent_firstname AS firstname, secondparent_lastname AS lastname')
            ->where(function ($q) {
                $q->where('secondparent_id', '!=', 0)
                    ->orWhere('secondparent_email', '!=', '');
            })
            ->get()
            ->map(fn ($r) => (array) $r)
            ->all();

        $createdUsers = 0;
        $linked = 0;
        $skipped = 0;

        foreach ($rows as $r) {
            $firstId = (int) ($r['first_id'] ?? 0);
            $secondId = (int) ($r['second_id'] ?? 0);
            $email = trim((string) ($r['email'] ?? ''));

            if ($firstId <= 0 || ($secondId <= 0 && $email === '')) {
                $skipped++;
                continue;
            }

            $tmp = 0;
            $familyId = $this->ensureFamilyForPrimaryParent($firstId, $tmp);

            $userId = 0;
            if ($secondId > 0) {
                $userId = $secondId;
            } else {
                $user = User::query()->where('email', $email)->first();
                if (!$user) {
                    $user = User::query()->create([
                        'firstname' => (string) ($r['firstname'] ?? ''),
                        'lastname' => (string) ($r['lastname'] ?? ''),
                        'email' => $email,
                        'status' => 'Active',
                        'user_type' => 'secondary',
                        'cellphone' => '',
                        'address_street' => '',
                        'city' => '',
                        'state' => '',
                        'zip' => '',
                        'accept_school_policy' => 1,
                        'password' => bcrypt('temporary'),
                        'semester' => '',
                    ]);
                    $createdUsers++;
                }
                $userId = (int) $user->id;
            }

            $students = DB::table('students')
                ->select('id')
                ->where('parent_id', $firstId)
                ->get()
                ->map(fn ($r) => (array) $r)
                ->all();
            foreach ($students as $sr) {
                $sid = (int) ($sr['id'] ?? 0);
                if ($sid > 0) {
                    $this->attachStudentToFamily($sid, $familyId);
                }
            }

            $linked += $this->attachGuardianUser($familyId, $userId, 'guardian', false, 1, 0);
        }

        return [
            'ok' => true,
            'created_users' => $createdUsers,
            'guardians_linked' => $linked,
            'skipped' => $skipped,
            'total_source' => count($rows),
        ];
    }

    private function ensureFamilyForPrimaryParent(int $primaryUserId, int &$createdCounter): int
    {
        $code = 'FAM-' . $primaryUserId;
        $row = Family::query()->where('family_code', $code)->first();
        if ($row) {
            return (int) $row->id;
        }

        $family = Family::query()->create([
            'family_code' => $code,
            'household_name' => 'Family of User ' . $primaryUserId,
            'is_active' => 1,
        ]);
        $createdCounter++;

        return (int) $family->id;
    }

    private function attachStudentToFamily(int $studentId, int $familyId): int
    {
        if ($studentId <= 0 || $familyId <= 0) {
            return 0;
        }

        return DB::table('family_students')->insertOrIgnore([
            'family_id' => $familyId,
            'student_id' => $studentId,
            'is_primary_home' => 1,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function attachGuardianUser(
        int $familyId,
        int $userId,
        string $relation = 'primary',
        bool $isPrimary = false,
        int $receiveEmails = 1,
        int $receiveSms = 0
    ): int {
        if ($familyId <= 0 || $userId <= 0) {
            return 0;
        }

        return DB::table('family_guardians')->insertOrIgnore([
            'family_id' => $familyId,
            'user_id' => $userId,
            'relation' => $relation,
            'is_primary' => $isPrimary ? 1 : 0,
            'receive_emails' => $receiveEmails,
            'receive_sms' => $receiveSms,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function familyIdFromStudentPrimary(int $studentId): ?int
    {
        $student = Student::query()->select('parent_id')->find($studentId);
        if (!$student || empty($student->parent_id)) {
            return null;
        }

        $code = 'FAM-' . (int) $student->parent_id;
        $row = Family::query()->select('id')->where('family_code', $code)->first();
        if ($row) {
            return (int) $row->id;
        }

        $fallback = DB::table('family_students')
            ->select('family_id')
            ->where('student_id', $studentId)
            ->orderByDesc('is_primary_home')
            ->first();

        return $fallback?->family_id ? (int) $fallback->family_id : null;
    }

    private function ensureTablesExist(array $tables): void
    {
        foreach ($tables as $table) {
            if (!Schema::hasTable($table)) {
                Log::warning('Family tables missing', ['table' => $table]);
                throw new \RuntimeException("Missing required table '{$table}'. Run migrations.");
            }
        }
    }
}
