<?php
/**
 * HR_Controller — مدیریت نیروی انسانی
 * بخش‌ها | سمت‌ها | کارمندان | حضور غیاب | مرخصی | تخصیص پروژه
 */

if ( ! defined( 'ABSPATH' ) ) exit;

class HR_Controller {

    public static function register_routes(): void {
        $ns = 'acc/v1';
        $p  = 'acc_jwt_check_permission';

        /* بخش‌ها */
        register_rest_route($ns, '/hr/departments',           [['methods'=>'GET','callback'=>[self::class,'get_departments'],'permission_callback'=>$p],
                                                                ['methods'=>'POST','callback'=>[self::class,'create_department'],'permission_callback'=>$p]]);
        register_rest_route($ns, '/hr/departments/(?P<id>\d+)', [['methods'=>'PUT','callback'=>[self::class,'update_department'],'permission_callback'=>$p],
                                                                  ['methods'=>'DELETE','callback'=>[self::class,'delete_department'],'permission_callback'=>$p]]);

        /* سمت‌ها */
        register_rest_route($ns, '/hr/positions',           [['methods'=>'GET','callback'=>[self::class,'get_positions'],'permission_callback'=>$p],
                                                              ['methods'=>'POST','callback'=>[self::class,'create_position'],'permission_callback'=>$p]]);
        register_rest_route($ns, '/hr/positions/(?P<id>\d+)', [['methods'=>'PUT','callback'=>[self::class,'update_position'],'permission_callback'=>$p],
                                                                ['methods'=>'DELETE','callback'=>[self::class,'delete_position'],'permission_callback'=>$p]]);

        /* کارمندان */
        register_rest_route($ns, '/hr/employees',           [['methods'=>'GET','callback'=>[self::class,'get_employees'],'permission_callback'=>$p],
                                                              ['methods'=>'POST','callback'=>[self::class,'create_employee'],'permission_callback'=>$p]]);
        register_rest_route($ns, '/hr/employees/(?P<id>\d+)', [['methods'=>'GET','callback'=>[self::class,'get_employee'],'permission_callback'=>$p],
                                                                ['methods'=>'PUT','callback'=>[self::class,'update_employee'],'permission_callback'=>$p],
                                                                ['methods'=>'DELETE','callback'=>[self::class,'delete_employee'],'permission_callback'=>$p]]);

        /* حضور غیاب */
        register_rest_route($ns, '/hr/attendance', [['methods'=>'GET','callback'=>[self::class,'get_attendance'],'permission_callback'=>$p],
                                                     ['methods'=>'POST','callback'=>[self::class,'check_in_out'],'permission_callback'=>$p]]);

        /* مرخصی */
        register_rest_route($ns, '/hr/leaves',           [['methods'=>'GET','callback'=>[self::class,'get_leaves'],'permission_callback'=>$p],
                                                          ['methods'=>'POST','callback'=>[self::class,'create_leave'],'permission_callback'=>$p]]);
        register_rest_route($ns, '/hr/leaves/(?P<id>\d+)', [['methods'=>'PUT','callback'=>[self::class,'update_leave'],'permission_callback'=>$p],
                                                            ['methods'=>'DELETE','callback'=>[self::class,'delete_leave'],'permission_callback'=>$p]]);

        /* تخصیص پروژه */
        register_rest_route($ns, '/hr/assignments',           [['methods'=>'GET','callback'=>[self::class,'get_assignments'],'permission_callback'=>$p],
                                                                ['methods'=>'POST','callback'=>[self::class,'create_assignment'],'permission_callback'=>$p]]);
        register_rest_route($ns, '/hr/assignments/(?P<id>\d+)', [['methods'=>'PUT','callback'=>[self::class,'update_assignment'],'permission_callback'=>$p],
                                                                  ['methods'=>'DELETE','callback'=>[self::class,'delete_assignment'],'permission_callback'=>$p]]);
    }

    /* ════════════════════ بخش‌ها ════════════════════ */
    public static function get_departments( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $rows = $wpdb->get_results(
            "SELECT d.*, m.first_name AS manager_first, m.last_name AS manager_last,
                    (SELECT COUNT(*) FROM {$wpdb->prefix}hr_employees WHERE department_id=d.id AND status='active') AS emp_count
             FROM {$wpdb->prefix}hr_departments d
             LEFT JOIN {$wpdb->prefix}hr_employees m ON m.id = d.manager_id
             WHERE d.is_active = 1
             ORDER BY d.parent_id, d.name",
            ARRAY_A
        );
        return new WP_REST_Response(['data' => $rows ?? []]);
    }

    public static function create_department( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $wpdb->insert($wpdb->prefix.'hr_departments', [
            'parent_id'   => (int)($req->get_param('parent_id') ?? 0),
            'code'        => sanitize_text_field($req->get_param('code') ?? ''),
            'name'        => sanitize_text_field($req->get_param('name') ?? ''),
            'manager_id'  => $req->get_param('manager_id') ? (int)$req->get_param('manager_id') : null,
            'description' => sanitize_textarea_field($req->get_param('description') ?? ''),
        ]);
        return new WP_REST_Response(['id'=>$wpdb->insert_id,'success'=>true],201);
    }

    public static function update_department( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $id = (int)$req->get_param('id');
        $data = [];
        foreach(['code','name','description'] as $k) {
            if ($req->get_param($k) !== null) $data[$k] = sanitize_textarea_field((string)$req->get_param($k));
        }
        if ($req->get_param('parent_id') !== null) $data['parent_id'] = (int)$req->get_param('parent_id');
        if ($req->get_param('manager_id') !== null) $data['manager_id'] = $req->get_param('manager_id') ? (int)$req->get_param('manager_id') : null;
        if ($data) $wpdb->update($wpdb->prefix.'hr_departments', $data, ['id'=>$id]);
        return new WP_REST_Response(['success'=>true]);
    }

    public static function delete_department( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $wpdb->update($wpdb->prefix.'hr_departments', ['is_active'=>0], ['id'=>(int)$req->get_param('id')]);
        return new WP_REST_Response(['success'=>true]);
    }

    /* ════════════════════ سمت‌ها ════════════════════ */
    public static function get_positions( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $rows = $wpdb->get_results(
            "SELECT p.*, d.name AS dept_name,
                    (SELECT COUNT(*) FROM {$wpdb->prefix}hr_employees WHERE position_id=p.id AND status='active') AS emp_count
             FROM {$wpdb->prefix}hr_positions p
             LEFT JOIN {$wpdb->prefix}hr_departments d ON d.id = p.department_id
             WHERE p.is_active = 1
             ORDER BY d.name, p.title",
            ARRAY_A
        );
        return new WP_REST_Response(['data' => $rows ?? []]);
    }

    public static function create_position( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $wpdb->insert($wpdb->prefix.'hr_positions', [
            'code'          => sanitize_text_field($req->get_param('code') ?? ''),
            'title'         => sanitize_text_field($req->get_param('title') ?? ''),
            'department_id' => $req->get_param('department_id') ? (int)$req->get_param('department_id') : null,
            'level'         => sanitize_text_field($req->get_param('level') ?? 'staff'),
            'description'   => sanitize_textarea_field($req->get_param('description') ?? ''),
        ]);
        return new WP_REST_Response(['id'=>$wpdb->insert_id,'success'=>true],201);
    }

    public static function update_position( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $id = (int)$req->get_param('id');
        $data = [];
        foreach(['code','title','level','description'] as $k) {
            if ($req->get_param($k) !== null) $data[$k] = sanitize_textarea_field((string)$req->get_param($k));
        }
        if ($req->get_param('department_id') !== null) $data['department_id'] = $req->get_param('department_id') ? (int)$req->get_param('department_id') : null;
        if ($data) $wpdb->update($wpdb->prefix.'hr_positions', $data, ['id'=>$id]);
        return new WP_REST_Response(['success'=>true]);
    }

    public static function delete_position( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $wpdb->update($wpdb->prefix.'hr_positions', ['is_active'=>0], ['id'=>(int)$req->get_param('id')]);
        return new WP_REST_Response(['success'=>true]);
    }

    /* ════════════════════ کارمندان ════════════════════ */
    public static function get_employees( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $pre = $wpdb->prefix;
        $wheres = ['e.status != %s'];
        $args = ['deleted'];

        if ($v = $req->get_param('department_id')) { $wheres[] = 'e.department_id = %d'; $args[] = (int)$v; }
        if ($v = $req->get_param('status'))        { $wheres[] = 'e.status = %s';        $args[] = sanitize_text_field($v); }
        if ($v = $req->get_param('search')) {
            $wheres[] = '(e.first_name LIKE %s OR e.last_name LIKE %s OR e.employee_code LIKE %s OR e.national_id LIKE %s)';
            $s = "%{$v}%"; $args[] = $s; $args[] = $s; $args[] = $s; $args[] = $s;
        }

        $where = 'WHERE ' . implode(' AND ', $wheres);
        $sql = "SELECT e.*, d.name AS dept_name, p.title AS position_title,
                       CONCAT(e.first_name,' ',e.last_name) AS full_name
                FROM {$pre}hr_employees e
                LEFT JOIN {$pre}hr_departments d ON d.id = e.department_id
                LEFT JOIN {$pre}hr_positions   p ON p.id = e.position_id
                {$where}
                ORDER BY e.last_name, e.first_name
                LIMIT 500";

        $rows = $wpdb->get_results($wpdb->prepare($sql, ...$args), ARRAY_A);
        return new WP_REST_Response(['data' => $rows ?? [], 'total' => count($rows ?? [])]);
    }

    public static function get_employee( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $pre = $wpdb->prefix;
        $id  = (int)$req->get_param('id');

        $emp = $wpdb->get_row($wpdb->prepare(
            "SELECT e.*, d.name AS dept_name, p.title AS position_title,
                    CONCAT(m.first_name,' ',m.last_name) AS manager_name
             FROM {$pre}hr_employees e
             LEFT JOIN {$pre}hr_departments d ON d.id = e.department_id
             LEFT JOIN {$pre}hr_positions   p ON p.id = e.position_id
             LEFT JOIN {$pre}hr_employees   m ON m.id = e.manager_id
             WHERE e.id = %d", $id
        ), ARRAY_A);

        if (!$emp) return new WP_REST_Response(['message'=>'یافت نشد'], 404);

        $emp['locations']   = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$pre}gis_locations WHERE entity_type='employee' AND entity_id=%d ORDER BY is_primary DESC", $id
        ), ARRAY_A) ?: [];

        $emp['leaves']      = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$pre}hr_leaves WHERE employee_id=%d ORDER BY from_date DESC LIMIT 20", $id
        ), ARRAY_A) ?: [];

        $emp['assignments'] = $wpdb->get_results($wpdb->prepare(
            "SELECT a.*, pr.name AS project_name FROM {$pre}hr_assignments a
             LEFT JOIN {$pre}pc_projects pr ON pr.id = a.project_id
             WHERE a.employee_id=%d ORDER BY a.from_date DESC LIMIT 20", $id
        ), ARRAY_A) ?: [];

        return new WP_REST_Response(['data' => $emp]);
    }

    public static function create_employee( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $data = self::_emp_data($req);
        if (!$data['first_name'] || !$data['last_name']) {
            return new WP_REST_Response(['message'=>'نام و نام خانوادگی الزامی است'], 400);
        }
        // تولید کد خودکار اگر نباشد
        if (!$data['employee_code']) {
            $last = (int) $wpdb->get_var("SELECT MAX(CAST(SUBSTRING(employee_code,4) AS UNSIGNED)) FROM {$wpdb->prefix}hr_employees WHERE employee_code LIKE 'EMP%'");
            $data['employee_code'] = 'EMP' . str_pad($last + 1, 5, '0', STR_PAD_LEFT);
        }
        $wpdb->insert($wpdb->prefix.'hr_employees', $data);
        return new WP_REST_Response(['id'=>$wpdb->insert_id,'employee_code'=>$data['employee_code'],'success'=>true], 201);
    }

    public static function update_employee( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $id = (int)$req->get_param('id');
        $data = self::_emp_data($req, true);
        if ($data) $wpdb->update($wpdb->prefix.'hr_employees', $data, ['id'=>$id]);
        return new WP_REST_Response(['success'=>true]);
    }

    public static function delete_employee( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $wpdb->update($wpdb->prefix.'hr_employees', ['status'=>'inactive'], ['id'=>(int)$req->get_param('id')]);
        return new WP_REST_Response(['success'=>true]);
    }

    private static function _emp_data( WP_REST_Request $req, bool $partial = false ): array {
        $fields = [
            'employee_code'=>'text', 'wp_user_id'=>'int_nullable',
            'first_name'=>'text', 'last_name'=>'text', 'national_id'=>'text', 'father_name'=>'text',
            'birth_date'=>'text', 'gender'=>'text', 'marital_status'=>'text',
            'phone'=>'text', 'mobile'=>'text', 'email'=>'text',
            'department_id'=>'int_nullable', 'position_id'=>'int_nullable', 'manager_id'=>'int_nullable',
            'hire_date'=>'text', 'end_date'=>'text', 'employment_type'=>'text',
            'base_salary'=>'float', 'bank_account'=>'text', 'iban'=>'text',
            'emergency_contact'=>'text', 'emergency_phone'=>'text',
            'photo_url'=>'text', 'status'=>'text', 'notes'=>'textarea',
        ];
        $data = [];
        foreach ($fields as $k => $type) {
            $v = $req->get_param($k);
            if ($partial && $v === null) continue;
            switch ($type) {
                case 'int_nullable': $data[$k] = $v ? (int)$v : null; break;
                case 'int':          $data[$k] = (int)$v; break;
                case 'float':        $data[$k] = (float)($v ?: 0); break;
                case 'textarea':     $data[$k] = sanitize_textarea_field((string)$v); break;
                default:             $data[$k] = sanitize_text_field((string)$v);
            }
        }
        return $data;
    }

    /* ════════════════════ حضور غیاب ════════════════════ */
    public static function get_attendance( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $pre = $wpdb->prefix;
        $wheres = []; $args = [];

        if ($v = $req->get_param('employee_id')) { $wheres[] = 'a.employee_id = %d'; $args[] = (int)$v; }
        if ($v = $req->get_param('from'))        { $wheres[] = 'a.date >= %s';       $args[] = sanitize_text_field($v); }
        if ($v = $req->get_param('to'))          { $wheres[] = 'a.date <= %s';       $args[] = sanitize_text_field($v); }

        $where = $wheres ? 'WHERE ' . implode(' AND ', $wheres) : '';
        $sql = "SELECT a.*, CONCAT(e.first_name,' ',e.last_name) AS employee_name
                FROM {$pre}hr_attendance a
                LEFT JOIN {$pre}hr_employees e ON e.id = a.employee_id
                {$where}
                ORDER BY a.date DESC, a.id DESC LIMIT 500";
        $rows = $args ? $wpdb->get_results($wpdb->prepare($sql, ...$args), ARRAY_A)
                      : $wpdb->get_results($sql, ARRAY_A);
        return new WP_REST_Response(['data' => $rows ?? []]);
    }

    public static function check_in_out( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $pre = $wpdb->prefix;
        $emp = (int)$req->get_param('employee_id');
        $date = sanitize_text_field($req->get_param('date') ?: date('Y-m-d'));
        $action = sanitize_text_field($req->get_param('action') ?? 'check_in');

        if (!$emp) return new WP_REST_Response(['message'=>'employee_id الزامی است'], 400);

        $existing = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$pre}hr_attendance WHERE employee_id=%d AND date=%s", $emp, $date
        ), ARRAY_A);

        $now = current_time('mysql');
        $lat = $req->get_param('lat') ? (float)$req->get_param('lat') : null;
        $lng = $req->get_param('lng') ? (float)$req->get_param('lng') : null;

        if ($action === 'check_in') {
            if ($existing) {
                $wpdb->update("{$pre}hr_attendance",
                    ['check_in'=>$now, 'check_in_lat'=>$lat, 'check_in_lng'=>$lng],
                    ['id'=>$existing['id']]);
            } else {
                $wpdb->insert("{$pre}hr_attendance", [
                    'employee_id'=>$emp, 'date'=>$date, 'check_in'=>$now,
                    'check_in_lat'=>$lat, 'check_in_lng'=>$lng, 'status'=>'present',
                ]);
            }
        } else {
            if (!$existing) return new WP_REST_Response(['message'=>'ابتدا check_in کنید'], 400);
            $hours = (strtotime($now) - strtotime($existing['check_in'])) / 3600;
            $wpdb->update("{$pre}hr_attendance",
                ['check_out'=>$now, 'check_out_lat'=>$lat, 'check_out_lng'=>$lng, 'hours'=>round($hours,2)],
                ['id'=>$existing['id']]);
        }

        return new WP_REST_Response(['success'=>true]);
    }

    /* ════════════════════ مرخصی ════════════════════ */
    public static function get_leaves( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $pre = $wpdb->prefix;
        $wheres = []; $args = [];

        if ($v = $req->get_param('employee_id')) { $wheres[] = 'l.employee_id = %d'; $args[] = (int)$v; }
        if ($v = $req->get_param('status'))      { $wheres[] = 'l.status = %s';      $args[] = sanitize_text_field($v); }

        $where = $wheres ? 'WHERE ' . implode(' AND ', $wheres) : '';
        $sql = "SELECT l.*, CONCAT(e.first_name,' ',e.last_name) AS employee_name
                FROM {$pre}hr_leaves l
                LEFT JOIN {$pre}hr_employees e ON e.id = l.employee_id
                {$where}
                ORDER BY l.from_date DESC LIMIT 300";
        $rows = $args ? $wpdb->get_results($wpdb->prepare($sql, ...$args), ARRAY_A)
                      : $wpdb->get_results($sql, ARRAY_A);
        return new WP_REST_Response(['data' => $rows ?? []]);
    }

    public static function create_leave( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $from = sanitize_text_field($req->get_param('from_date') ?? '');
        $to   = sanitize_text_field($req->get_param('to_date') ?? $from);
        $days = $from && $to ? (strtotime($to) - strtotime($from)) / 86400 + 1 : 1;

        $wpdb->insert($wpdb->prefix.'hr_leaves', [
            'employee_id' => (int)$req->get_param('employee_id'),
            'leave_type'  => sanitize_text_field($req->get_param('leave_type') ?? 'annual'),
            'from_date'   => $from, 'to_date' => $to, 'days' => $days,
            'reason'      => sanitize_textarea_field($req->get_param('reason') ?? ''),
            'status'      => 'pending',
        ]);
        return new WP_REST_Response(['id'=>$wpdb->insert_id,'success'=>true], 201);
    }

    public static function update_leave( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $id = (int)$req->get_param('id');
        $data = [];
        foreach(['leave_type','from_date','to_date','reason','status'] as $k) {
            if ($req->get_param($k) !== null) $data[$k] = sanitize_textarea_field((string)$req->get_param($k));
        }
        if (isset($data['status']) && in_array($data['status'], ['approved','rejected'])) {
            $data['approved_at'] = current_time('mysql');
            $data['approved_by'] = (int) get_current_user_id();
        }
        if ($data) $wpdb->update($wpdb->prefix.'hr_leaves', $data, ['id'=>$id]);
        return new WP_REST_Response(['success'=>true]);
    }

    public static function delete_leave( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $wpdb->delete($wpdb->prefix.'hr_leaves', ['id'=>(int)$req->get_param('id')]);
        return new WP_REST_Response(['success'=>true]);
    }

    /* ════════════════════ تخصیص پروژه ════════════════════ */
    public static function get_assignments( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $pre = $wpdb->prefix;
        $wheres = ['a.is_active = 1']; $args = [];
        if ($v = $req->get_param('employee_id')) { $wheres[] = 'a.employee_id = %d'; $args[] = (int)$v; }
        if ($v = $req->get_param('project_id'))  { $wheres[] = 'a.project_id = %d';  $args[] = (int)$v; }

        $where = 'WHERE ' . implode(' AND ', $wheres);
        $sql = "SELECT a.*, CONCAT(e.first_name,' ',e.last_name) AS employee_name,
                       p.name AS project_name
                FROM {$pre}hr_assignments a
                LEFT JOIN {$pre}hr_employees e ON e.id = a.employee_id
                LEFT JOIN {$pre}pc_projects   p ON p.id = a.project_id
                {$where}
                ORDER BY a.from_date DESC LIMIT 300";
        $rows = $args ? $wpdb->get_results($wpdb->prepare($sql, ...$args), ARRAY_A)
                      : $wpdb->get_results($sql, ARRAY_A);
        return new WP_REST_Response(['data' => $rows ?? []]);
    }

    public static function create_assignment( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $wpdb->insert($wpdb->prefix.'hr_assignments', [
            'employee_id' => (int)$req->get_param('employee_id'),
            'project_id'  => $req->get_param('project_id') ? (int)$req->get_param('project_id') : null,
            'task_id'     => $req->get_param('task_id') ? (int)$req->get_param('task_id') : null,
            'role'        => sanitize_text_field($req->get_param('role') ?? ''),
            'from_date'   => sanitize_text_field($req->get_param('from_date') ?: date('Y-m-d')),
            'to_date'     => sanitize_text_field($req->get_param('to_date') ?? '') ?: null,
            'allocation'  => (float)($req->get_param('allocation') ?? 100),
            'notes'       => sanitize_text_field($req->get_param('notes') ?? ''),
        ]);
        return new WP_REST_Response(['id'=>$wpdb->insert_id,'success'=>true], 201);
    }

    public static function update_assignment( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $id = (int)$req->get_param('id');
        $data = [];
        foreach(['role','from_date','to_date','notes'] as $k) {
            if ($req->get_param($k) !== null) $data[$k] = sanitize_text_field((string)$req->get_param($k));
        }
        if ($req->get_param('allocation') !== null) $data['allocation'] = (float)$req->get_param('allocation');
        if ($req->get_param('is_active')  !== null) $data['is_active']  = (int)$req->get_param('is_active');
        if ($data) $wpdb->update($wpdb->prefix.'hr_assignments', $data, ['id'=>$id]);
        return new WP_REST_Response(['success'=>true]);
    }

    public static function delete_assignment( WP_REST_Request $req ): WP_REST_Response {
        global $wpdb;
        $wpdb->update($wpdb->prefix.'hr_assignments', ['is_active'=>0], ['id'=>(int)$req->get_param('id')]);
        return new WP_REST_Response(['success'=>true]);
    }
}
