<?php
declare(strict_types=1);

namespace App\Modules\HR\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Modules\HR\Models\HrDepartment;
use App\Modules\HR\Models\HrDepartmentPosition;
use App\Modules\HR\Models\HrEmployeeProfile;
use App\Modules\HR\Models\HrJobTitle;

class DepartmentController extends Controller
{
    public function index(Request $request): Response
    {
        $filters = [
            'q'               => trim((string) $request->get('q', '')),
            'branch_id'       => trim((string) $request->get('branch_id', '')),
            'department_type' => trim((string) $request->get('department_type', '')),
            'parent_id'       => trim((string) $request->get('parent_id', '')),
        ];

        $page = max(1, (int) $request->get('page', 1));
        $result = HrDepartment::search($filters, 25, $page);

        $db = App::getInstance()->db();
        $branches = $db->select("SELECT id, name_ar FROM branches WHERE is_active = 1 ORDER BY name_ar");
        $idaras = HrDepartment::allIdaras();

        return $this->view('HR.Views.departments.index', [
            'departments' => $result['data'],
            'pagination'  => $result['pagination'],
            'filters'     => $filters,
            'branches'    => $branches,
            'idaras'      => $idaras,
        ]);
    }

    public function create(Request $request): Response
    {
        $db = App::getInstance()->db();
        $idaras = HrDepartment::allIdaras();
        $branches = $db->select("SELECT id, name_ar FROM branches WHERE is_active = 1 ORDER BY name_ar");
        $employees = HrEmployeeProfile::getActiveIds();

        return $this->view('HR.Views.departments.form', [
            'department'  => null,
            'idaras'      => $idaras,
            'branches'    => $branches,
            'employees'   => $employees,
        ]);
    }

    public function store(Request $request): Response
    {
        $data = $this->extractData($request);
        $errors = $this->validateInput($data);

        if (!empty($errors)) {
            return $this->flashErrorsAndRedirect($errors, $request, '/hr/departments/create');
        }

        $department = HrDepartment::create($data);

        return $this->redirect('/hr/departments/' . $department->id)->withSuccess('تم إنشاء القسم بنجاح');
    }

    public function show(Request $request, string $id): Response
    {
        $department = HrDepartment::find((int) $id);
        if (!$department) {
            return $this->redirect('/hr/departments')->withError('القسم غير موجود');
        }

        $db = App::getInstance()->db();

        $parent = $department->parent_id ? HrDepartment::find((int) $department->parent_id) : null;

        $manager = $department->manager_employee_id
            ? $db->selectOne("SELECT hp.id, hp.first_name_ar, hp.last_name_ar FROM hr_employee_profiles hp WHERE hp.employee_id = ? AND hp.is_archived = 0", [(int) $department->manager_employee_id])
            : null;

        $branch = $department->branch_id
            ? $db->selectOne("SELECT id, name_ar FROM branches WHERE id = ?", [(int) $department->branch_id])
            : null;

        $children = $db->select(
            "SELECT id, name_ar, department_code FROM hr_departments WHERE parent_id = ? AND is_archived = 0 ORDER BY name_ar",
            [(int) $id]
        );

        $employeeCount = $db->selectOne(
            "SELECT COUNT(*) as cnt FROM hr_employee_profiles WHERE department_id = ? AND employment_status = 'active' AND is_archived = 0",
            [(int) $id]
        );

        $positions = HrDepartmentPosition::getStaffingReport((int) $id);

        return $this->view('HR.Views.departments.show', [
            'department'    => $department,
            'parent'        => $parent,
            'manager'       => $manager,
            'branch'        => $branch,
            'children'      => $children,
            'employeeCount' => (int) ($employeeCount['cnt'] ?? 0),
            'positions'     => $positions,
        ]);
    }

    public function edit(Request $request, string $id): Response
    {
        $department = HrDepartment::find((int) $id);
        if (!$department) {
            return $this->redirect('/hr/departments')->withError('القسم غير موجود');
        }

        $db = App::getInstance()->db();
        $idaras = HrDepartment::allIdaras();
        $branches = $db->select("SELECT id, name_ar FROM branches WHERE is_active = 1 ORDER BY name_ar");
        $employees = HrEmployeeProfile::getActiveIds();

        return $this->view('HR.Views.departments.form', [
            'department'  => $department,
            'idaras'      => $idaras,
            'branches'    => $branches,
            'employees'   => $employees,
        ]);
    }

    public function update(Request $request, string $id): Response
    {
        $department = HrDepartment::find((int) $id);
        if (!$department) {
            return $this->redirect('/hr/departments')->withError('القسم غير موجود');
        }

        $data = $this->extractData($request);
        $errors = $this->validateInput($data);

        // Prevent circular parent
        if ((int) ($data['parent_id'] ?? 0) === (int) $id) {
            $errors[] = 'لا يمكن أن يكون القسم هو الأب لنفسه';
        }

        if (!empty($errors)) {
            return $this->flashErrorsAndRedirect($errors, $request, '/hr/departments/' . $id . '/edit');
        }

        $department->update($data);

        return $this->redirect('/hr/departments/' . $id)->withSuccess('تم تحديث القسم بنجاح');
    }

    public function archive(Request $request, string $id): Response
    {
        $department = HrDepartment::find((int) $id);
        if (!$department) {
            return $this->redirect('/hr/departments')->withError('القسم غير موجود');
        }

        $db = App::getInstance()->db();
        $employeeCount = $db->selectOne(
            "SELECT COUNT(*) as cnt FROM hr_employee_profiles WHERE department_id = ? AND employment_status = 'active' AND is_archived = 0",
            [(int) $id]
        );

        if ((int) ($employeeCount['cnt'] ?? 0) > 0) {
            return $this->redirect('/hr/departments/' . $id)->withError('لا يمكن حذف قسم يحتوي على موظفين نشطين');
        }

        $childCount = $db->selectOne(
            "SELECT COUNT(*) as cnt FROM hr_departments WHERE parent_id = ? AND is_archived = 0",
            [(int) $id]
        );

        if ((int) ($childCount['cnt'] ?? 0) > 0) {
            return $this->redirect('/hr/departments/' . $id)->withError('لا يمكن حذف قسم يحتوي على أقسام فرعية');
        }

        $department->archive();

        return $this->redirect('/hr/departments')->withSuccess('تم حذف القسم بنجاح');
    }

    public function positions(Request $request, string $id): Response
    {
        $department = HrDepartment::find((int) $id);
        if (!$department) {
            return $this->redirect('/hr/departments')->withError('القسم غير موجود');
        }

        $positions = HrDepartmentPosition::getStaffingReport((int) $id);
        $jobTitles = HrJobTitle::allActive();

        return $this->view('HR.Views.departments.positions', [
            'department' => $department,
            'positions'  => $positions,
            'jobTitles'  => $jobTitles,
        ]);
    }

    public function storePosition(Request $request, string $id): Response
    {
        $department = HrDepartment::find((int) $id);
        if (!$department) {
            return $this->redirect('/hr/departments')->withError('القسم غير موجود');
        }

        $jobTitleId = (int) $request->post('job_title_id', 0);
        $authorizedCount = (int) $request->post('authorized_count', 0);

        $errors = [];
        if ($jobTitleId <= 0) {
            $errors[] = 'يجب اختيار مسمى وظيفي';
        }
        if ($authorizedCount <= 0) {
            $errors[] = 'العدد المعتمد يجب أن يكون أكبر من صفر';
        }

        if (!empty($errors)) {
            return $this->flashErrorsAndRedirect($errors, $request, '/hr/departments/' . $id . '/positions');
        }

        // Check if position already exists for this department + job title
        $db = App::getInstance()->db();
        $existing = $db->selectOne(
            "SELECT id FROM hr_department_positions WHERE department_id = ? AND job_title_id = ?",
            [(int) $id, $jobTitleId]
        );

        if ($existing) {
            $db->update('hr_department_positions', [
                'authorized_count' => $authorizedCount,
                'updated_at'       => date('Y-m-d H:i:s'),
            ], '`id` = ?', [(int) $existing['id']]);
        } else {
            HrDepartmentPosition::create([
                'department_id'    => (int) $id,
                'job_title_id'     => $jobTitleId,
                'authorized_count' => $authorizedCount,
            ]);
        }

        return $this->redirect('/hr/departments/' . $id . '/positions')->withSuccess('تم حفظ الوظيفة المعتمدة بنجاح');
    }

    public function deletePosition(Request $request, string $id, string $posId): Response
    {
        $department = HrDepartment::find((int) $id);
        if (!$department) {
            return $this->redirect('/hr/departments')->withError('القسم غير موجود');
        }

        $db = App::getInstance()->db();
        $position = $db->selectOne(
            "SELECT id FROM hr_department_positions WHERE id = ? AND department_id = ?",
            [(int) $posId, (int) $id]
        );

        if (!$position) {
            return $this->redirect('/hr/departments/' . $id . '/positions')->withError('الوظيفة غير موجودة');
        }

        $db->delete('hr_department_positions', '`id` = ?', [(int) $posId]);

        return $this->redirect('/hr/departments/' . $id . '/positions')->withSuccess('تم حذف الوظيفة المعتمدة بنجاح');
    }

    public function aqsamJson(Request $request, string $id): Response
    {
        $aqsam = HrDepartment::getAqsamByIdara((int) $id);
        return $this->json(['results' => $aqsam]);
    }

    private function extractData(Request $request): array
    {
        $type = trim((string) $request->post('department_type', 'qism'));
        if (!in_array($type, ['idara', 'qism'], true)) {
            $type = 'qism';
        }

        return [
            'name_ar'    => trim((string) $request->post('name_ar', '')),
            'name_en'    => trim((string) $request->post('name_en', '')) ?: null,
            'department_code' => strtoupper(trim((string) $request->post('department_code', ''))),
            'department_type' => $type,
            'parent_id'       => $type === 'qism' ? (((int) $request->post('parent_id', 0)) ?: null) : null,
            'manager_employee_id' => ((int) $request->post('manager_employee_id', 0)) ?: null,
            'branch_id'  => ((int) $request->post('branch_id', 0)) ?: null,
            'staffing_capacity' => ((int) $request->post('staffing_capacity', 0)) ?: null,
            'is_active'  => (int) ($request->post('is_active', 1)),
        ];
    }

    private function validateInput(array $data): array
    {
        $errors = [];
        $typeLabel = $data['department_type'] === 'idara' ? 'الإدارة' : 'القسم';
        if ($data['name_ar'] === '' || mb_strlen($data['name_ar']) < 2) {
            $errors[] = "اسم {$typeLabel} بالعربي مطلوب (حرفان على الأقل)";
        }
        if ($data['department_code'] === '') {
            $errors[] = "كود {$typeLabel} مطلوب";
        }
        if ($data['department_type'] === 'qism' && empty($data['parent_id'])) {
            $errors[] = 'يجب اختيار الإدارة التابع لها القسم';
        }
        return $errors;
    }

    private function flashErrorsAndRedirect(array $errors, Request $request, string $url): Response
    {
        $session = App::getInstance()->session();
        $session->flash('_alerts', array_map(fn($e) => ['type' => 'error', 'message' => $e], $errors));
        $session->flash('_old_input', $request->all());
        return $this->redirect($url);
    }
}
