<?php

namespace App\Http\Controllers;

use App\Http\Requests\School\ImportStudentsRequest;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Inertia\Inertia;
use Inertia\Response;

class ImportController extends Controller
{
    public function students(): Response
    {
        $schoolId = $this->currentSchoolId(request());

        $jobs = $schoolId
            ? DB::table('import_jobs')
                ->where('school_id', $schoolId)
                ->where('type', 'students')
                ->latest('created_at')
                ->limit(8)
                ->get(['status', 'total_rows', 'valid_rows', 'invalid_rows', 'created_at'])
            : collect();

        return Inertia::render('Imports/ImportStudents', [
            'jobs' => $jobs->map(fn ($job): array => [
                'status' => $this->importStatusLabel($job->status),
                'total' => (int) $job->total_rows,
                'valid' => (int) $job->valid_rows,
                'invalid' => (int) $job->invalid_rows,
                'createdAt' => $job->created_at ? $this->jalaliDate($job->created_at, true) : '—',
            ])->values(),
        ]);
    }

    public function storeStudents(ImportStudentsRequest $request): RedirectResponse
    {
        $schoolId = $this->currentSchoolId($request);

        abort_unless($schoolId, 422, 'مدرسه مشخص نیست.');

        $file = $request->file('file');
        $path = $file->store('imports/students', 'local');
        $handle = fopen($file->getRealPath(), 'r');

        if (! $handle) {
            return back()->withErrors(['file' => 'فایل قابل خواندن نیست.']);
        }

        $headers = fgetcsv($handle);
        $total = 0;
        $valid = 0;
        $invalid = 0;

        $jobId = DB::table('import_jobs')->insertGetId([
            'school_id' => $schoolId,
            'type' => 'students',
            'file_path' => $path,
            'status' => 'processing',
            'created_by' => $request->user()?->id,
            'started_at' => now(),
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        while (($row = fgetcsv($handle)) !== false) {
            $total++;
            if (! $headers || count($headers) !== count($row)) {
                $invalid++;
                DB::table('import_job_rows')->insert([
                    'import_job_id' => $jobId,
                    'row_index' => $total,
                    'raw_data' => json_encode($row, JSON_UNESCAPED_UNICODE),
                    'status' => 'invalid',
                    'errors' => json_encode(['تعداد ستون‌ها با header فایل برابر نیست.'], JSON_UNESCAPED_UNICODE),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                continue;
            }

            $data = array_combine($headers, $row) ?: [];
            $errors = $this->validateStudentRow($data);

            if ($errors) {
                $invalid++;
                DB::table('import_job_rows')->insert([
                    'import_job_id' => $jobId,
                    'row_index' => $total,
                    'raw_data' => json_encode($data, JSON_UNESCAPED_UNICODE),
                    'status' => 'invalid',
                    'errors' => json_encode($errors, JSON_UNESCAPED_UNICODE),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                continue;
            }

            $valid++;
            $gradeId = $this->gradeIdByNumber($data['grade_level'] ?? null);
            $classroomId = $this->classroomIdByName((int) $schoolId, $data['classroom_name'] ?? null, $gradeId);

            DB::transaction(function () use ($schoolId, $data, $gradeId, $classroomId, $jobId, $total): void {
                $userId = null;

                if (! empty($data['username']) && (! empty($data['password']) || ! empty($data['password_hash']))) {
                    $userId = DB::table('users')->updateOrInsert(
                        ['username' => $data['username']],
                        [
                            'school_id' => $schoolId,
                            'password' => ! empty($data['password_hash']) ? $data['password_hash'] : Hash::make($data['password']),
                            'first_name' => $data['first_name'],
                            'last_name' => $data['last_name'],
                            'mobile' => $data['mobile'] ?? null,
                            'role_key' => 'student',
                            'status' => 'active',
                            'must_change_password' => true,
                            'must_complete_profile' => true,
                            'created_at' => now(),
                            'updated_at' => now(),
                        ]
                    );

                    $userId = DB::table('users')->where('username', $data['username'])->value('id');
                }

                $studentId = DB::table('students')->updateOrInsert(
                    ['school_id' => $schoolId, 'student_code' => $data['student_code']],
                    [
                        'user_id' => $userId,
                        'first_name' => $data['first_name'],
                        'last_name' => $data['last_name'],
                        'national_code' => $data['national_code'] ?? null,
                        'mobile' => $data['mobile'] ?? null,
                        'father_mobile' => $data['father_mobile'] ?? null,
                        'mother_mobile' => $data['mother_mobile'] ?? null,
                        'home_phone' => $data['home_phone'] ?? null,
                        'birth_date_jalali' => $data['birth_date_jalali'] ?? null,
                        'gender' => $data['gender'] ?? null,
                        'grade_level_id' => $gradeId,
                        'address' => $data['address'] ?? null,
                        'status' => $data['status'] ?? 'active',
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]
                );

                $studentId = DB::table('students')->where('school_id', $schoolId)->where('student_code', $data['student_code'])->value('id');

                if ($classroomId && $studentId) {
                    DB::table('class_students')->updateOrInsert(
                        ['school_id' => $schoolId, 'classroom_id' => $classroomId, 'student_id' => $studentId, 'status' => 'active'],
                        ['created_at' => now(), 'updated_at' => now()]
                    );
                }

                DB::table('import_job_rows')->insert([
                    'import_job_id' => $jobId,
                    'row_index' => $total,
                    'raw_data' => json_encode($data, JSON_UNESCAPED_UNICODE),
                    'status' => 'imported',
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            });
        }

        fclose($handle);

        DB::table('import_jobs')->where('id', $jobId)->update([
            'status' => $invalid > 0 ? 'failed' : 'completed',
            'total_rows' => $total,
            'valid_rows' => $valid,
            'invalid_rows' => $invalid,
            'finished_at' => now(),
            'updated_at' => now(),
        ]);

        return redirect()->route('school.students')->with('success', "Import تمام شد. معتبر: {$valid} / خطادار: {$invalid}");
    }

    public function teachers(): Response
    {
        $schoolId = $this->currentSchoolId(request());

        $jobs = $schoolId
            ? DB::table('import_jobs')
                ->where('school_id', $schoolId)
                ->where('type', 'teachers')
                ->latest('created_at')
                ->limit(8)
                ->get(['status', 'total_rows', 'valid_rows', 'invalid_rows', 'created_at'])
            : collect();

        return Inertia::render('Imports/ImportTeachers', [
            'jobs' => $jobs->map(fn ($job): array => [
                'status' => $this->importStatusLabel($job->status),
                'total' => (int) $job->total_rows,
                'valid' => (int) $job->valid_rows,
                'invalid' => (int) $job->invalid_rows,
                'createdAt' => $job->created_at ? $this->jalaliDate($job->created_at, true) : '—',
            ])->values(),
        ]);
    }

    public function storeTeachers(Request $request): RedirectResponse
    {
        $schoolId = $this->currentSchoolId($request);
        abort_unless($schoolId, 422, 'مدرسه مشخص نیست.');

        $request->validate(['file' => ['required', 'file', 'mimes:csv,txt', 'max:2048']]);

        $file = $request->file('file');
        $path = $file->store('imports/teachers', 'local');
        $handle = fopen($file->getRealPath(), 'r');

        if (! $handle) {
            return back()->withErrors(['file' => 'فایل قابل خواندن نیست.']);
        }

        $headers = fgetcsv($handle);
        $total = 0;
        $valid = 0;
        $invalid = 0;

        $jobId = DB::table('import_jobs')->insertGetId([
            'school_id' => $schoolId,
            'type' => 'teachers',
            'file_path' => $path,
            'status' => 'processing',
            'created_by' => $request->user()?->id,
            'started_at' => now(),
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        while (($row = fgetcsv($handle)) !== false) {
            $total++;
            if (! $headers || count($headers) !== count($row)) {
                $invalid++;
                DB::table('import_job_rows')->insert([
                    'import_job_id' => $jobId,
                    'row_index' => $total,
                    'raw_data' => json_encode($row, JSON_UNESCAPED_UNICODE),
                    'status' => 'invalid',
                    'errors' => json_encode(['تعداد ستون‌ها با header فایل برابر نیست.'], JSON_UNESCAPED_UNICODE),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                continue;
            }

            $data = array_combine($headers, $row) ?: [];
            $errors = $this->validateTeacherRow($data);

            if ($errors) {
                $invalid++;
                DB::table('import_job_rows')->insert([
                    'import_job_id' => $jobId,
                    'row_index' => $total,
                    'raw_data' => json_encode($data, JSON_UNESCAPED_UNICODE),
                    'status' => 'invalid',
                    'errors' => json_encode($errors, JSON_UNESCAPED_UNICODE),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                continue;
            }

            $valid++;
            DB::transaction(function () use ($schoolId, $data, $jobId, $total): void {
                DB::table('teachers')->updateOrInsert(
                    ['school_id' => $schoolId, 'teacher_code' => $data['teacher_code']],
                    [
                        'first_name' => $data['first_name'],
                        'last_name' => $data['last_name'],
                        'national_code' => $data['national_code'] ?? null,
                        'mobile' => $data['mobile'] ?? null,
                        'email' => $data['email'] ?? null,
                        'specialty' => $data['subjects'] ?? null,
                        'status' => in_array($data['status'] ?? '', ['active', 'inactive']) ? $data['status'] : 'active',
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]
                );

                DB::table('import_job_rows')->insert([
                    'import_job_id' => $jobId,
                    'row_index' => $total,
                    'raw_data' => json_encode($data, JSON_UNESCAPED_UNICODE),
                    'status' => 'imported',
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            });
        }

        fclose($handle);

        DB::table('import_jobs')->where('id', $jobId)->update([
            'status' => $invalid > 0 ? 'failed' : 'completed',
            'total_rows' => $total,
            'valid_rows' => $valid,
            'invalid_rows' => $invalid,
            'finished_at' => now(),
            'updated_at' => now(),
        ]);

        return redirect()->route('school.teachers')->with('success', "Import معلمان تمام شد. معتبر: {$valid} / خطادار: {$invalid}");
    }

    public function users(): Response
    {
        $schoolId = $this->currentSchoolId(request());

        $jobs = $schoolId
            ? DB::table('import_jobs')
                ->where('school_id', $schoolId)
                ->where('type', 'users')
                ->latest('created_at')
                ->limit(8)
                ->get(['status', 'total_rows', 'valid_rows', 'invalid_rows', 'created_at'])
            : collect();

        return Inertia::render('Imports/ImportUsers', [
            'jobs' => $jobs->map(fn ($job): array => [
                'status' => $this->importStatusLabel($job->status),
                'total' => (int) $job->total_rows,
                'valid' => (int) $job->valid_rows,
                'invalid' => (int) $job->invalid_rows,
                'createdAt' => $job->created_at ? $this->jalaliDate($job->created_at, true) : '—',
            ])->values(),
        ]);
    }

    public function storeUsers(Request $request): RedirectResponse
    {
        $schoolId = $this->currentSchoolId($request);
        abort_unless($schoolId, 422, 'مدرسه مشخص نیست.');

        $request->validate(['file' => ['required', 'file', 'mimes:csv,txt', 'max:2048']]);

        $file = $request->file('file');
        $path = $file->store('imports/users', 'local');
        $handle = fopen($file->getRealPath(), 'r');

        if (! $handle) {
            return back()->withErrors(['file' => 'فایل قابل خواندن نیست.']);
        }

        $headers = fgetcsv($handle);
        $total = 0;
        $valid = 0;
        $invalid = 0;

        $jobId = DB::table('import_jobs')->insertGetId([
            'school_id' => $schoolId,
            'type' => 'users',
            'file_path' => $path,
            'status' => 'processing',
            'created_by' => $request->user()?->id,
            'started_at' => now(),
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        $allowedRoles = ['teacher', 'moaven', 'support', 'finance', 'principal'];

        while (($row = fgetcsv($handle)) !== false) {
            $total++;
            if (! $headers || count($headers) !== count($row)) {
                $invalid++;
                DB::table('import_job_rows')->insert([
                    'import_job_id' => $jobId,
                    'row_index' => $total,
                    'raw_data' => json_encode($row, JSON_UNESCAPED_UNICODE),
                    'status' => 'invalid',
                    'errors' => json_encode(['تعداد ستون‌ها با header فایل برابر نیست.'], JSON_UNESCAPED_UNICODE),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                continue;
            }

            $data = array_combine($headers, $row) ?: [];
            $errors = $this->validateUserRow($data, $allowedRoles);

            if ($errors) {
                $invalid++;
                DB::table('import_job_rows')->insert([
                    'import_job_id' => $jobId,
                    'row_index' => $total,
                    'raw_data' => json_encode($data, JSON_UNESCAPED_UNICODE),
                    'status' => 'invalid',
                    'errors' => json_encode($errors, JSON_UNESCAPED_UNICODE),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                continue;
            }

            $valid++;
            DB::transaction(function () use ($schoolId, $data, $jobId, $total): void {
                $passwordHash = ! empty($data['password_hash'])
                    ? $data['password_hash']
                    : (! empty($data['temporary_password']) ? Hash::make($data['temporary_password']) : Hash::make('Changeme@123'));

                DB::table('users')->updateOrInsert(
                    ['username' => $data['username']],
                    [
                        'school_id' => $schoolId,
                        'first_name' => $data['first_name'],
                        'last_name' => $data['last_name'],
                        'mobile' => $data['mobile'] ?? null,
                        'email' => $data['email'] ?? null,
                        'role_key' => $data['role'],
                        'password' => $passwordHash,
                        'status' => in_array($data['status'] ?? '', ['active', 'inactive']) ? $data['status'] : 'active',
                        'must_change_password' => filter_var($data['force_password_change'] ?? 'true', FILTER_VALIDATE_BOOLEAN),
                        'must_complete_profile' => filter_var($data['must_complete_profile'] ?? 'true', FILTER_VALIDATE_BOOLEAN),
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]
                );

                DB::table('import_job_rows')->insert([
                    'import_job_id' => $jobId,
                    'row_index' => $total,
                    'raw_data' => json_encode(array_merge($data, ['temporary_password' => '***', 'password_hash' => '***']), JSON_UNESCAPED_UNICODE),
                    'status' => 'imported',
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            });
        }

        fclose($handle);

        DB::table('import_jobs')->where('id', $jobId)->update([
            'status' => $invalid > 0 ? 'failed' : 'completed',
            'total_rows' => $total,
            'valid_rows' => $valid,
            'invalid_rows' => $invalid,
            'finished_at' => now(),
            'updated_at' => now(),
        ]);

        return redirect()->route('school.users')->with('success', "Import کاربران تمام شد. معتبر: {$valid} / خطادار: {$invalid}");
    }

    private function validateTeacherRow(array $data): array
    {
        $errors = [];
        foreach (['teacher_code', 'first_name', 'last_name'] as $required) {
            if (empty($data[$required])) {
                $errors[] = "{$required} خالی است.";
            }
        }
        if (! empty($data['mobile']) && ! preg_match('/^09\d{9}$/', $data['mobile'])) {
            $errors[] = 'mobile معتبر نیست.';
        }
        return $errors;
    }

    private function validateUserRow(array $data, array $allowedRoles): array
    {
        $errors = [];
        foreach (['username', 'first_name', 'last_name', 'role'] as $required) {
            if (empty($data[$required])) {
                $errors[] = "{$required} خالی است.";
            }
        }
        if (! empty($data['role']) && ! in_array($data['role'], $allowedRoles)) {
            $errors[] = 'نقش معتبر نیست. مجاز: '.implode(', ', $allowedRoles);
        }
        if (! empty($data['mobile']) && ! preg_match('/^09\d{9}$/', $data['mobile'])) {
            $errors[] = 'mobile معتبر نیست.';
        }
        return $errors;
    }

    private function validateStudentRow(array $data): array
    {
        $errors = [];

        foreach (['student_code', 'first_name', 'last_name', 'grade_level'] as $required) {
            if (empty($data[$required])) {
                $errors[] = "{$required} خالی است.";
            }
        }

        foreach (['mobile', 'father_mobile', 'mother_mobile'] as $phone) {
            if (! empty($data[$phone]) && ! preg_match('/^09\d{9}$/', $data[$phone])) {
                $errors[] = "{$phone} معتبر نیست.";
            }
        }

        return $errors;
    }

    private function gradeIdByNumber(?string $number): ?int
    {
        if (! $number) {
            return null;
        }

        return DB::table('grade_levels')->where('number', (int) $number)->value('id');
    }

    private function classroomIdByName(int $schoolId, ?string $name, ?int $gradeId): ?int
    {
        if (! $name || ! $gradeId) {
            return null;
        }

        return DB::table('classrooms')->where('school_id', $schoolId)->where('name', $name)->value('id')
            ?: DB::table('classrooms')->insertGetId([
                'school_id' => $schoolId,
                'grade_level_id' => $gradeId,
                'name' => $name,
                'status' => 'active',
                'created_at' => now(),
                'updated_at' => now(),
            ]);
    }

    private function importStatusLabel(string $status): string
    {
        return match ($status) {
            'processing' => 'در حال پردازش',
            'completed' => 'کامل',
            'failed' => 'دارای خطا',
            default => $status,
        };
    }
}
