<?php
/**
 * Contact Lists REST API Endpoint.
 *
 * @package BoostBot
 * @since   1.0.0
 */

// Prevent direct access
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Class BoostBot_Contact_Lists_Endpoint
 *
 * Handles REST API endpoints for contact lists.
 *
 * @since 1.0.0
 */
class BoostBot_Contact_Lists_Endpoint extends BoostBot_Base_Endpoint {

    /**
     * REST base for this endpoint.
     *
     * @var string
     */
    protected $rest_base = 'contact-lists';

    /**
     * Register routes for this endpoint.
     *
     * @return void
     */
    public function register() {
        // GET /contact-lists - List all contact lists
        $this->register_route(
            '',
            'GET',
            array( $this, 'get_lists' ),
            array( $this, 'admin_access' )
        );

        // POST /contact-lists - Create contact list
        $this->register_route(
            '',
            'POST',
            array( $this, 'create_list' ),
            array( $this, 'admin_access' )
        );

        // GET /contact-lists/{id} - Get single list with contacts
        $this->register_route(
            '/(?P<id>\d+)',
            'GET',
            array( $this, 'get_list' ),
            array( $this, 'admin_access' )
        );

        // PUT /contact-lists/{id} - Update contact list
        $this->register_route(
            '/(?P<id>\d+)',
            'PUT',
            array( $this, 'update_list' ),
            array( $this, 'admin_access' )
        );

        // DELETE /contact-lists/{id} - Delete contact list
        $this->register_route(
            '/(?P<id>\d+)',
            'DELETE',
            array( $this, 'delete_list' ),
            array( $this, 'admin_access' )
        );

        // PUT /contact-lists/{id}/primary - Set as primary
        $this->register_route(
            '/(?P<id>\d+)/primary',
            'PUT',
            array( $this, 'set_primary' ),
            array( $this, 'admin_access' )
        );

        // POST /contact-lists/{id}/import - Import contacts from CSV
        $this->register_route(
            '/(?P<id>\d+)/import',
            'POST',
            array( $this, 'import_contacts' ),
            array( $this, 'admin_access' )
        );

        // POST /contact-lists/{id}/contacts - Add contact
        $this->register_route(
            '/(?P<id>\d+)/contacts',
            'POST',
            array( $this, 'add_contact' ),
            array( $this, 'admin_access' )
        );

        // PUT /contact-lists/{list_id}/contacts/{id} - Update contact
        $this->register_route(
            '/(?P<list_id>\d+)/contacts/(?P<id>\d+)',
            'PUT',
            array( $this, 'update_contact' ),
            array( $this, 'admin_access' )
        );

        // DELETE /contact-lists/{list_id}/contacts/{id} - Delete contact
        $this->register_route(
            '/(?P<list_id>\d+)/contacts/(?P<id>\d+)',
            'DELETE',
            array( $this, 'delete_contact' ),
            array( $this, 'admin_access' )
        );

        // PUT /contact-lists/{id}/contacts/order - Update contacts order
        $this->register_route(
            '/(?P<id>\d+)/contacts/order',
            'PUT',
            array( $this, 'update_contacts_order' ),
            array( $this, 'admin_access' )
        );

        // GET /contact-lists/dropdown - Get for dropdown
        $this->register_route(
            '/dropdown',
            'GET',
            array( $this, 'get_dropdown' ),
            array( $this, 'admin_access' )
        );

        // POST /contact-lists/{id}/duplicate - Duplicate list with all contacts
        $this->register_route(
            '/(?P<id>\d+)/duplicate',
            'POST',
            array( $this, 'duplicate_list' ),
            array( $this, 'admin_access' )
        );
    }

    /**
     * Get all contact lists.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response
     */
    public function get_lists( $request ) {
        $model            = new BoostBot_Contact_List_Model();
        $include_contacts = $request->get_param( 'include_contacts' );

        $lists = $model->get_all_with_counts( array(
            'orderby' => 'is_primary',
            'order'   => 'DESC',
            'limit'   => 100,
        ) );

        // If include_contacts is requested, fetch contacts for each list
        if ( $include_contacts ) {
            $contact_model = new BoostBot_Contact_Model();
            foreach ( $lists as &$list ) {
                $list->contacts = $contact_model->get_by_list( $list->id );
                // Parse JSON fields in contacts
                if ( is_array( $list->contacts ) ) {
                    foreach ( $list->contacts as &$contact ) {
                        $contact = $this->parse_contact_json( $contact );
                    }
                }
            }
        }

        return $this->success( array( 'lists' => $lists ) );
    }

    /**
     * Get single contact list with contacts.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function get_list( $request ) {
        $id    = absint( $request->get_param( 'id' ) );
        $model = new BoostBot_Contact_List_Model();

        $list = $model->get_with_contacts( $id );

        if ( ! $list ) {
            return $this->not_found( 'Contact List' );
        }

        // Parse JSON fields in contacts
        if ( isset( $list->contacts ) && is_array( $list->contacts ) ) {
            foreach ( $list->contacts as &$contact ) {
                $contact = $this->parse_contact_json( $contact );
            }
        }

        return $this->success( array( 'list' => $list ) );
    }

    /**
     * Create new contact list.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function create_list( $request ) {
        $model = new BoostBot_Contact_List_Model();
        $data  = $request->get_json_params();

        $id = $model->create( $data );

        if ( is_wp_error( $id ) ) {
            return $this->error( $id->get_error_message(), 400 );
        }

        if ( ! $id ) {
            return $this->error( __( 'Failed to create contact list', 'boostbot' ), 400 );
        }

        $list = $model->get( $id );

        if ( class_exists( 'BoostBot_Logger' ) ) {
            BoostBot_Logger::info( 'Contact list created', array( 'id' => $id, 'name' => $list->name ) );
        }

        return $this->success( array(
            'list'    => $list,
            'message' => __( 'Contact list created successfully', 'boostbot' ),
        ), 201 );
    }

    /**
     * Update contact list.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function update_list( $request ) {
        $id    = absint( $request->get_param( 'id' ) );
        $model = new BoostBot_Contact_List_Model();

        $existing = $model->get( $id );
        if ( ! $existing ) {
            return $this->not_found( 'Contact List' );
        }

        $data   = $request->get_json_params();
        $result = $model->update( $id, $data );

        if ( ! $result ) {
            return $this->error( __( 'Failed to update contact list', 'boostbot' ), 400 );
        }

        // If setting as primary, use the dedicated method
        if ( ! empty( $data['is_primary'] ) && ! $existing->is_primary ) {
            $model->set_primary( $id );
        }

        $list = $model->get( $id );

        return $this->success( array(
            'list'    => $list,
            'message' => __( 'Contact list updated successfully', 'boostbot' ),
        ) );
    }

    /**
     * Delete contact list.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function delete_list( $request ) {
        $id    = absint( $request->get_param( 'id' ) );
        $model = new BoostBot_Contact_List_Model();

        $existing = $model->get( $id );
        if ( ! $existing ) {
            return $this->not_found( 'Contact List' );
        }

        $result = $model->delete( $id );

        if ( ! $result ) {
            return $this->error( __( 'Failed to delete contact list', 'boostbot' ), 400 );
        }

        if ( class_exists( 'BoostBot_Logger' ) ) {
            BoostBot_Logger::info( 'Contact list deleted', array( 'id' => $id ) );
        }

        return $this->success( array(
            'message' => __( 'Contact list deleted successfully', 'boostbot' ),
        ) );
    }

    /**
     * Set contact list as primary.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function set_primary( $request ) {
        $id    = absint( $request->get_param( 'id' ) );
        $model = new BoostBot_Contact_List_Model();

        $existing = $model->get( $id );
        if ( ! $existing ) {
            return $this->not_found( 'Contact List' );
        }

        $result = $model->set_primary( $id );

        if ( ! $result ) {
            return $this->error( __( 'Failed to set primary contact list', 'boostbot' ), 400 );
        }

        return $this->success( array(
            'message' => __( 'Primary contact list updated', 'boostbot' ),
        ) );
    }

    /**
     * Import contacts from CSV file or base64 content.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function import_contacts( $request ) {
        $list_id = absint( $request->get_param( 'id' ) );
        $model   = new BoostBot_Contact_List_Model();

        // Verify list exists
        $list = $model->get( $list_id );
        if ( ! $list ) {
            return $this->not_found( 'Contact List' );
        }

        // Try to get CSV content from multiple sources
        $csv_content = null;
        
        // Method 1: Check for base64 content in JSON body (workaround for servers without temp folder)
        $json_params = $request->get_json_params();
        if ( ! empty( $json_params['csv_content'] ) ) {
            $csv_content = $json_params['csv_content'];
            // If it's base64 encoded, decode it
            if ( ! empty( $json_params['is_base64'] ) ) {
                $csv_content = base64_decode( $csv_content ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- decoding uploaded CSV data
            }
        }
        
        // Method 2: Check for direct content parameter
        if ( ! $csv_content && ! empty( $json_params['content'] ) ) {
            $csv_content = $json_params['content'];
        }
        
        // Method 3: Try file upload (traditional method)
        if ( ! $csv_content ) {
            $files = $request->get_file_params();
            
            if ( ! empty( $files['file'] ) ) {
                $file = $files['file'];
                
                // Check for upload errors
                if ( ! empty( $file['error'] ) && UPLOAD_ERR_OK !== $file['error'] ) {
                    // If temp folder missing, suggest using base64 method
                    if ( UPLOAD_ERR_NO_TMP_DIR === $file['error'] ) {
                        return $this->error( 
                            __( 'Server temp folder not configured. Please use the alternative import method.', 'boostbot' ), 
                            400 
                        );
                    }
                    
                    $error_messages = array(
                        UPLOAD_ERR_INI_SIZE   => 'File too large (server limit)',
                        UPLOAD_ERR_FORM_SIZE  => 'File too large (form limit)',
                        UPLOAD_ERR_PARTIAL    => 'File only partially uploaded',
                        UPLOAD_ERR_NO_FILE    => 'No file was uploaded',
                        UPLOAD_ERR_CANT_WRITE => 'Failed to write file',
                        UPLOAD_ERR_EXTENSION  => 'Upload blocked by extension',
                    );
                    $error_msg = $error_messages[ $file['error'] ] ?? 'Unknown upload error';
                    return $this->error( $error_msg, 400 );
                }
                
                // Read file content
                if ( ! empty( $file['tmp_name'] ) && file_exists( $file['tmp_name'] ) ) {
                    $csv_content = file_get_contents( $file['tmp_name'] ); // phpcs:ignore
                }
            }
        }
        
        // No content found
        if ( ! $csv_content ) {
            return $this->error( __( 'No CSV content provided', 'boostbot' ), 400 );
        }

        // Import contacts from content
        $imported = $model->import_contacts_from_content( $list_id, $csv_content );

        if ( is_wp_error( $imported ) ) {
            return $this->error( $imported->get_error_message(), 400 );
        }

        return $this->success( array(
            'message'  => sprintf(
                /* translators: %d: number of imported contacts */
                __( '%d contacts imported successfully', 'boostbot' ),
                $imported
            ),
            'imported' => $imported,
        ) );
    }

    /**
     * Add contact to list.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function add_contact( $request ) {
        $list_id       = absint( $request->get_param( 'id' ) );
        $list_model    = new BoostBot_Contact_List_Model();
        $contact_model = new BoostBot_Contact_Model();

        // Verify list exists
        $list = $list_model->get( $list_id );
        if ( ! $list ) {
            return $this->not_found( 'Contact List' );
        }

        $data            = $request->get_json_params();
        $data['list_id'] = $list_id;

        $id = $contact_model->create( $data );

        if ( is_wp_error( $id ) ) {
            return $this->error( $id->get_error_message(), 400 );
        }

        if ( ! $id ) {
            return $this->error( __( 'Failed to add contact', 'boostbot' ), 400 );
        }

        $contact = $contact_model->get( $id );
        $contact = $this->parse_contact_json( $contact );

        return $this->success( array(
            'contact' => $contact,
            'message' => __( 'Contact added successfully', 'boostbot' ),
        ), 201 );
    }

    /**
     * Update contact.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function update_contact( $request ) {
        $list_id       = absint( $request->get_param( 'list_id' ) );
        $contact_id    = absint( $request->get_param( 'id' ) );
        $contact_model = new BoostBot_Contact_Model();

        $existing = $contact_model->get( $contact_id );
        if ( ! $existing || (int) $existing->list_id !== $list_id ) {
            return $this->not_found( 'Contact' );
        }

        $data   = $request->get_json_params();
        $result = $contact_model->update( $contact_id, $data );

        if ( ! $result ) {
            return $this->error( __( 'Failed to update contact', 'boostbot' ), 400 );
        }

        $contact = $contact_model->get( $contact_id );
        $contact = $this->parse_contact_json( $contact );

        return $this->success( array(
            'contact' => $contact,
            'message' => __( 'Contact updated successfully', 'boostbot' ),
        ) );
    }

    /**
     * Delete contact.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function delete_contact( $request ) {
        $list_id       = absint( $request->get_param( 'list_id' ) );
        $contact_id    = absint( $request->get_param( 'id' ) );
        $contact_model = new BoostBot_Contact_Model();

        $existing = $contact_model->get( $contact_id );
        if ( ! $existing || (int) $existing->list_id !== $list_id ) {
            return $this->not_found( 'Contact' );
        }

        $result = $contact_model->delete( $contact_id );

        if ( ! $result ) {
            return $this->error( __( 'Failed to delete contact', 'boostbot' ), 400 );
        }

        return $this->success( array(
            'message' => __( 'Contact deleted successfully', 'boostbot' ),
        ) );
    }

    /**
     * Update contacts order.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function update_contacts_order( $request ) {
        $contact_model = new BoostBot_Contact_Model();
        $data          = $request->get_json_params();

        if ( empty( $data['order'] ) || ! is_array( $data['order'] ) ) {
            return $this->error( __( 'Invalid order data', 'boostbot' ), 400 );
        }

        $result = $contact_model->update_order( $data['order'] );

        if ( ! $result ) {
            return $this->error( __( 'Failed to update contacts order', 'boostbot' ), 400 );
        }

        return $this->success( array(
            'message' => __( 'Contacts order updated', 'boostbot' ),
        ) );
    }

    /**
     * Get contact lists for dropdown.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response
     */
    public function get_dropdown( $request ) {
        $model = new BoostBot_Contact_List_Model();
        $lists = $model->get_for_dropdown();

        return $this->success( array( 'lists' => $lists ) );
    }

    /**
     * Duplicate a contact list including all its contacts.
     *
     * @param WP_REST_Request $request The request.
     * @return WP_REST_Response|WP_Error
     */
    public function duplicate_list( $request ) {
        $id         = absint( $request->get_param( 'id' ) );
        $list_model = new BoostBot_Contact_List_Model();

        $original = $list_model->get_with_contacts( $id );
        if ( ! $original ) {
            return $this->not_found( 'Contact List' );
        }

        // Create the new list.
        $new_list_id = $list_model->create( array(
            'name'        => $original->name . __( ' (העתק)', 'boostbot' ),
            'description' => $original->description,
            'is_primary'  => 0,
        ) );

        if ( ! $new_list_id ) {
            return $this->error( __( 'Failed to duplicate contact list', 'boostbot' ), 500 );
        }

        // Duplicate all contacts into the new list.
        $contact_model    = new BoostBot_Contact_Model();
        $contacts_created = 0;

        if ( ! empty( $original->contacts ) && is_array( $original->contacts ) ) {
            foreach ( $original->contacts as $contact ) {
                $contact_data = array(
                    'list_id'              => $new_list_id,
                    'name'                 => $contact->name,
                    'title'                => $contact->title,
                    'department'           => $contact->department,
                    'phone'                => $contact->phone,
                    'email'                => $contact->email,
                    'whatsapp'             => $contact->whatsapp,
                    'description'          => $contact->description,
                    'meeting_availability' => $contact->meeting_availability, // Already JSON string.
                    'specialties'          => $contact->specialties,          // Already JSON string.
                    'sort_order'           => $contact->sort_order,
                );

                $cid = $contact_model->create( $contact_data );
                if ( $cid ) {
                    $contacts_created++;
                }
            }
        }

        $new_list = $list_model->get_with_contacts( $new_list_id );
        if ( $new_list && isset( $new_list->contacts ) && is_array( $new_list->contacts ) ) {
            foreach ( $new_list->contacts as &$contact ) {
                $contact = $this->parse_contact_json( $contact );
            }
        }

        if ( class_exists( 'BoostBot_Logger' ) ) {
            BoostBot_Logger::info( 'Contact list duplicated', array(
                'original_id'     => $id,
                'new_id'          => $new_list_id,
                'contacts_copied' => $contacts_created,
            ) );
        }

        return $this->success( array(
            'list'    => $new_list,
            'message' => sprintf(
                /* translators: %d: number of contacts copied */
                __( 'Contact list duplicated with %d contacts', 'boostbot' ),
                $contacts_created
            ),
        ), 201 );
    }

    /**
     * Parse JSON fields in contact object.
     *
     * @param object $contact The contact object.
     * @return object The contact with parsed JSON fields.
     */
    private function parse_contact_json( $contact ) {
        if ( isset( $contact->availability ) ) {
            unset( $contact->availability );
        }

        if ( isset( $contact->specialties ) && is_string( $contact->specialties ) ) {
            $contact->specialties = json_decode( $contact->specialties, true );
            if ( ! is_array( $contact->specialties ) ) {
                $contact->specialties = array();
            }
        }

        if ( isset( $contact->meeting_availability ) && is_string( $contact->meeting_availability ) ) {
            $decoded = json_decode( $contact->meeting_availability, true );
            $contact->meeting_availability = is_array( $decoded ) ? $decoded : null;
        }

        return $contact;
    }
}

