<?php

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

class CPM_Controller {

    /* -------------------------------------------------------------------------- */
    /*   PROJECTS HANDLERS                                                        */
    /* -------------------------------------------------------------------------- */

    public static function get_projects( WP_REST_Request $request ) {
        global $wpdb;
        $p_table  = $wpdb->prefix . 'cp_projects';
        $s_table  = $wpdb->prefix . 'cp_project_statuses';
        $w_table  = $wpdb->prefix . 'cp_wbs';
        $t_table  = $wpdb->prefix . 'cp_tasks';
        $r_table  = $wpdb->prefix . 'cp_resources';
        $a_table  = $wpdb->prefix . 'cp_task_assignments';
        $d_table  = $wpdb->prefix . 'cp_task_dependencies';
        $c_table  = $wpdb->prefix . 'cp_calendars';
        $cd_table = $wpdb->prefix . 'cp_calendar_days';
        $fi_table = $wpdb->prefix . 'cp_financial_items';
        $tc_table = $wpdb->prefix . 'cp_task_costs';
        $pc_table = $wpdb->prefix . 'cp_project_costs';
        $cf_table = $wpdb->prefix . 'cp_cashflow';

        $sql = "SELECT p.id, p.name, p.code, COALESCE(s.code, 'planned') AS status,
                COUNT(DISTINCT c.id) AS calendars, COUNT(DISTINCT cd.id) AS calendar_days,
                COUNT(DISTINCT w.id) AS wbs, COUNT(DISTINCT t.id) AS tasks,
                COUNT(DISTINCT d.id) AS dependencies, COUNT(DISTINCT r.id) AS resources,
                COUNT(DISTINCT a.id) AS assignments, COUNT(DISTINCT fi.id) AS financial_items,
                COUNT(DISTINCT tc.id) AS task_costs, COUNT(DISTINCT pc.id) AS project_costs,
                COUNT(DISTINCT cf.id) AS cashflow, COALESCE(AVG(t.progress), 0) AS progress
                FROM {$p_table} p
                LEFT JOIN {$s_table} s ON s.id = p.status_id
                LEFT JOIN {$c_table} c ON c.project_id = p.id
                LEFT JOIN {$cd_table} cd ON cd.calendar_id = c.id
                LEFT JOIN {$w_table} w ON w.project_id = p.id
                LEFT JOIN {$t_table} t ON t.project_id = p.id
                LEFT JOIN {$d_table} d ON d.project_id = p.id
                LEFT JOIN {$r_table} r ON r.project_id = p.id
                LEFT JOIN {$a_table} a ON a.project_id = p.id
                LEFT JOIN {$fi_table} fi ON fi.project_id = p.id
                LEFT JOIN {$tc_table} tc ON tc.project_id = p.id
                LEFT JOIN {$pc_table} pc ON pc.project_id = p.id
                LEFT JOIN {$cf_table} cf ON cf.project_id = p.id
                GROUP BY p.id, p.name, p.code, s.code ORDER BY p.id DESC";

        $projects = $wpdb->get_results( $sql, ARRAY_A );
        if ( $wpdb->last_error ) return new WP_Error( 'cpm_projects_query_failed', $wpdb->last_error, array( 'status' => 500 ) );
        return rest_ensure_response( $projects );
    }

    public static function get_project_full( WP_REST_Request $request ) {
        global $wpdb;
        $project_id = (int) $request['id'];
        $project = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_projects WHERE id = %d", $project_id), ARRAY_A);
        if ( ! $project ) return new WP_Error( 'cpm_project_not_found', 'Project not found', array( 'status' => 404 ) );

        $calendars = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_calendars WHERE project_id = %d", $project_id), ARRAY_A);
        $cal_ids = wp_list_pluck( $calendars, 'id' );
        $cal_days = !empty($cal_ids) ? $wpdb->get_results("SELECT * FROM {$wpdb->prefix}cp_calendar_days WHERE calendar_id IN (" . implode(',', array_map('intval', $cal_ids)) . ")", ARRAY_A) : [];
        
        $wbs = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_wbs WHERE project_id = %d", $project_id), ARRAY_A);
        $tasks = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_tasks WHERE project_id = %d", $project_id), ARRAY_A);
        $deps = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_dependencies WHERE project_id = %d", $project_id), ARRAY_A);
        $resources = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_resources WHERE project_id = %d", $project_id), ARRAY_A);
        $assigns = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_assignments WHERE project_id = %d", $project_id), ARRAY_A);
        $finance = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_financial_items WHERE project_id = %d", $project_id), ARRAY_A);
        $t_costs = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_task_costs WHERE project_id = %d", $project_id), ARRAY_A);
        $p_cost = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_project_costs WHERE project_id = %d", $project_id), ARRAY_A);
        $cashflow = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_cashflow WHERE project_id = %d", $project_id), ARRAY_A);

        $data = [
            'project' => ['id' => (int)$project['id'], 'code' => $project['code'], 'name' => $project['name'], 'description' => $project['description'], 'startDate' => $project['start_date'], 'endDate' => $project['end_date'], 'status' => $project['status'], 'currency' => $project['currency']],
            'calendars' => array_map(['self', 'map_calendar'], $calendars),
            'calendarDays' => array_map(['self', 'map_calendar_day'], $cal_days),
            'wbs' => array_map(['self', 'map_wbs'], $wbs),
            'tasks' => array_map(['self', 'map_task'], $tasks),
            'dependencies' => array_map(['self', 'map_dependency'], $deps),
            'resources' => self::group_resources_by_type($resources),
            'assignments' => array_map(['self', 'map_assignment'], $assigns),
            'financialItems' => array_map(['self', 'map_financial_item'], $finance),
            'taskCosts' => array_map(['self', 'map_task_cost'], $t_costs),
            'projectCosts' => $p_cost ? self::map_project_cost($p_cost) : null,
            'cashflow' => array_map(['self', 'map_cashflow'], $cashflow),
        ];
        return new WP_REST_Response($data, 200);
    }

    /* -------------------------------------------------------------------------- */
    /*   TASKS HANDLERS                                                           */
    /* -------------------------------------------------------------------------- */

    public static function get_project_tasks( WP_REST_Request $request ) {
        global $wpdb;
        $tasks = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_tasks WHERE project_id = %d", (int)$request['id']), ARRAY_A);
        return new WP_REST_Response(array_map(['self', 'map_task'], $tasks), 200);
    }

    public static function create_task( WP_REST_Request $request ) {
        global $wpdb;
        $project_id = (int) $request['id'];
        $params = $request->get_json_params();
        if ( empty($params['wbsId']) || empty($params['name']) ) return new WP_Error('cpm_invalid_input', 'Missing fields', ['status' => 400]);

        $insert = [
            'project_id' => $project_id, 'wbs_id' => (int)$params['wbsId'], 'name' => trim($params['name']),
            'code' => isset($params['code']) ? trim($params['code']) : null,
            'description' => isset($params['description']) ? trim($params['description']) : null,
            'duration' => isset($params['duration']) ? (float)$params['duration'] : 0.0,
            'calendar_id' => isset($params['calendarId']) ? (int)$params['calendarId'] : null,
            'status' => isset($params['status']) ? trim($params['status']) : 'planned',
            'progress' => isset($params['progress']) ? (float)$params['progress'] : 0.0,
        ];
        $wpdb->insert($wpdb->prefix . 'cp_tasks', array_filter($insert, function($v){ return $v !== null; }));
        return new WP_REST_Response(self::map_task($wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_tasks WHERE id = %d", $wpdb->insert_id), ARRAY_A)), 201);
    }

    public static function update_task( WP_REST_Request $request ) {
        global $wpdb;
        $task_id = (int)$request['id'];
        $existing = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_tasks WHERE id = %d", $task_id), ARRAY_A);
        if (!$existing) return new WP_Error('cpm_task_not_found', 'Not found', ['status' => 404]);

        $params = $request->get_json_params();
        $map = ['wbsId'=>'wbs_id', 'code'=>'code', 'name'=>'name', 'description'=>'description', 'duration'=>'duration', 'calendarId'=>'calendar_id', 'status'=>'status', 'progress'=>'progress'];
        $data = [];
        foreach($map as $k=>$db) if(array_key_exists($k, $params)) $data[$db] = $params[$k];

        if(empty($data)) return new WP_Error('cpm_no_data', 'No data', ['status' => 400]);
        $wpdb->update($wpdb->prefix . 'cp_tasks', $data, ['id' => $task_id]);
        return new WP_REST_Response(self::map_task($wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}cp_tasks WHERE id = %d", $task_id), ARRAY_A)), 200);
    }

    public static function delete_task( WP_REST_Request $request ) {
        global $wpdb;
        $task_id = (int)$request['id'];
        if (!$wpdb->get_var($wpdb->prepare("SELECT id FROM {$wpdb->prefix}cp_tasks WHERE id = %d", $task_id))) return new WP_Error('404', 'Not found', ['status' => 404]);
        $wpdb->delete($wpdb->prefix . 'cp_tasks', ['id' => $task_id]);
        return new WP_REST_Response(['deleted' => true, 'id' => $task_id], 200);
    }

    /* -------------------------------------------------------------------------- */
    /*   MAP FUNCTIONS (Static)                                                   */
    /* -------------------------------------------------------------------------- */

    public static function map_calendar($r) { return ['id'=>(int)$r['id'], 'projectId'=>(int)$r['project_id'], 'name'=>$r['name'], 'description'=>$r['description'], 'type'=>$r['type'], 'config'=>$r['config'] ? json_decode($r['config'], true) : null]; }
    public static function map_calendar_day($r) { return ['id'=>(int)$r['id'], 'calendarId'=>(int)$r['calendar_id'], 'date'=>$r['date'], 'isWorking'=>(bool)$r['is_working'], 'note'=>$r['note']]; }
    public static function map_wbs($r) { return ['id'=>(int)$r['id'], 'projectId'=>(int)$r['project_id'], 'parentId'=>$r['parent_id']?(int)$r['parent_id']:null, 'code'=>$r['code'], 'name'=>$r['name'], 'sortIndex'=>(int)$r['sort_index']]; }
    public static function map_task($r) { return ['id'=>(int)$r['id'], 'projectId'=>(int)$r['project_id'], 'wbsId'=>(int)$r['wbs_id'], 'code'=>$r['code'], 'name'=>$r['name'], 'description'=>$r['description'], 'duration'=>(float)$r['duration'], 'calendarId'=>$r['calendar_id']?(int)$r['calendar_id']:null, 'earlyStart'=>$r['early_start'], 'earlyFinish'=>$r['early_finish'], 'lateStart'=>$r['late_start'], 'lateFinish'=>$r['late_finish'], 'totalFloat'=>(float)$r['total_float'], 'isCritical'=>(bool)$r['is_critical'], 'status'=>$r['status'], 'progress'=>(float)$r['progress']]; }
    public static function map_dependency($r) { return ['id'=>(int)$r['id'], 'projectId'=>(int)$r['project_id'], 'predecessorId'=>(int)$r['predecessor_id'], 'successorId'=>(int)$r['successor_id'], 'type'=>$r['type'], 'lag'=>(float)$r['lag']]; }
    public static function map_resource($r) { return ['id'=>(int)$r['id'], 'projectId'=>(int)$r['project_id'], 'type'=>$r['type'], 'code'=>$r['code'], 'name'=>$r['name'], 'unit'=>$r['unit'], 'costPerUnit'=>(float)$r['cost_per_unit'], 'currency'=>$r['currency'], 'calendarId'=>$r['calendar_id']?(int)$r['calendar_id']:null, 'attributes'=>$r['attributes']?json_decode($r['attributes'], true):null, 'isActive'=>(bool)$r['is_active']]; }
    public static function map_assignment($r) { return ['id'=>(int)$r['id'], 'projectId'=>(int)$r['project_id'], 'taskId'=>(int)$r['task_id'], 'resourceId'=>(int)$r['resource_id'], 'quantity'=>(float)$r['quantity'], 'costPerUnit'=>(float)$r['cost_per_unit'], 'totalCost'=>(float)$r['total_cost'], 'notes'=>$r['notes']]; }
    public static function map_financial_item($r) { return ['id'=>(int)$r['id'], 'projectId'=>(int)$r['project_id'], 'taskId'=>$r['task_id']?(int)$r['task_id']:null, 'category'=>$r['category'], 'description'=>$r['description'], 'amount'=>(float)$r['amount'], 'currency'=>$r['currency'], 'date'=>$r['date']]; }
    public static function map_task_cost($r) { return ['id'=>(int)$r['id'], 'projectId'=>(int)$r['project_id'], 'taskId'=>(int)$r['task_id'], 'costResources'=>(float)$r['cost_resources'], 'costFinancial'=>(float)$r['cost_financial'], 'costTotal'=>(float)$r['cost_total'], 'currency'=>$r['currency'], 'lastCalcAt'=>$r['last_calc_at']]; }
    public static function map_project_cost($r) { return ['id'=>(int)$r['id'], 'projectId'=>(int)$r['project_id'], 'costDirect'=>(float)$r['cost_direct'], 'costIndirect'=>(float)$r['cost_indirect'], 'costOverhead'=>(float)$r['cost_overhead'], 'costTotal'=>(float)$r['cost_total'], 'currency'=>$r['currency'], 'lastCalcAt'=>$r['last_calc_at']]; }
    public static function map_cashflow($r) { return ['id'=>(int)$r['id'], 'projectId'=>(int)$r['project_id'], 'periodDate'=>$r['period_date'], 'inflow'=>(float)$r['inflow'], 'outflow'=>(float)$r['outflow'], 'netFlow'=>(float)$r['net_flow'], 'currency'=>$r['currency']]; }

    public static function group_resources_by_type($rows) {
        $g = ['human'=>[], 'equipment'=>[], 'material'=>[], 'other'=>[]];
        foreach ($rows as $r) { $m = self::map_resource($r); $g[$m['type']][] = $m; }
        return $g;
    }
}
