<?php

add_filter( 'adfoin_action_providers', 'adfoin_attio_actions', 10 );

function adfoin_attio_actions( $actions ) {

    $actions['attio'] = [
        'title' => __( 'Attio CRM', 'advanced-form-integration' ),
        'tasks' => [
            'subscribe'   => __( 'Create or Update Record', 'advanced-form-integration' ),
        ]
    ];

    return $actions;
}

add_filter( 'adfoin_settings_tabs', 'adfoin_attio_settings_tab', 10 );

function adfoin_attio_settings_tab( $providers ) {
    $providers['attio'] = __( 'Attio CRM', 'advanced-form-integration' );

    return $providers;
}

add_action( 'adfoin_settings_view', 'adfoin_attio_settings_view', 10 );

function adfoin_attio_settings_view( $current_tab ) {
    if( $current_tab != 'attio' ) {
        return;
    }

    if ( ! class_exists( 'ADFOIN_Account_Manager' ) ) {
        require_once plugin_dir_path( __FILE__ ) . '../../includes/class-adfoin-account-manager.php';
    }

    $fields = array(
        array(
            'name'          => 'accessToken',
            'label'         => __( 'Access Token', 'advanced-form-integration' ),
            'type'          => 'password',
            'required'      => true,
            'mask'          => true,
            'placeholder'   => __( 'Paste your Attio access token', 'advanced-form-integration' ),
            'show_in_table' => true,
        ),
    );

    $instructions = sprintf(
        '<ol><li>%s</li><li>%s</li><li>%s</li><li>%s</li></ol>',
        __( 'Navigate to Workspace settings &gt; Developers.', 'advanced-form-integration' ),
        __( 'Create a new Access token and assign it a name.', 'advanced-form-integration' ),
        __( 'Under scopes, select "Read-write" for all or at least the necessary ones. Click Save Changes button.', 'advanced-form-integration' ),
        __( 'Copy the Access Token and add it here.', 'advanced-form-integration' )
    );

    ADFOIN_Account_Manager::render_settings_view(
        'attio',
        __( 'Attio CRM', 'advanced-form-integration' ),
        $fields,
        $instructions
    );
}

/*
 * Attio Credentials List
 */
function adfoin_attio_get_credentials_list() {
    $credentials = adfoin_read_credentials( 'attio' );

    foreach ($credentials as $option) {
        printf('<option value="%s">%s</option>', esc_attr($option['id']), esc_html($option['title']));
    }
}

add_action( 'adfoin_action_fields', 'adfoin_attio_action_fields' );
/*
 * Attio Action Fields
 */
function adfoin_attio_action_fields() {
    ?>
    <script type='text/template' id='attio-action-template'>
            <table class='form-table'>
                <tr valign='top' v-if="action.task == 'subscribe'">
                    <th scope='row'>
                        <?php esc_attr_e( 'Map Fields', 'advanced-form-integration' ); ?>
                    </th>
                    <td scope='row'>
                    <div class="afi-spinner" v-bind:class="{'is-active': fieldsLoading}"></div>
                    </td>
                </tr>

                <tr valign="top" class="alternate" v-if="action.task == 'subscribe'">
                    <td scope="row-title">
                        <label for="tablecell">
                            <?php esc_attr_e( 'Attio Account', 'advanced-form-integration' ); ?>
                        </label>
                    </td>
                    <td>
                        <select name="fieldData[credId]" v-model="fielddata.credId" @change="getObjects">
                        <option value=""> <?php _e( 'Select Account...', 'advanced-form-integration' ); ?> </option>
                            <?php
                                adfoin_attio_get_credentials_list();
                            ?>
                        </select>
                        <a href="<?php echo admin_url( 'admin.php?page=advanced-form-integration-settings&tab=attio' ); ?>" target="_blank">
                            <span class="dashicons dashicons-admin-settings"></span> <?php esc_html_e( 'Manage Accounts', 'advanced-form-integration' ); ?>
                        </a>
                    </td>
                </tr>

                <tr valign='top' class='alternate' v-if="action.task == 'subscribe'">
                    <td scope='row-title'>
                        <label for='tablecell'>
                            <?php esc_attr_e( 'Object', 'advanced-form-integration' ); ?>
                        </label>
                    </td>
                    <td>
                        <select name="fieldData[objectId]" v-model="fielddata.objectId" @change=getFields>
                            <option value=''> <?php _e( 'Select Object...', 'advanced-form-integration' ); ?> </option>
                            <option v-for='(item, index) in fielddata.objects' :value='index' > {{item}}  </option>
                        </select>
                        <div class="afi-spinner" v-bind:class="{'is-active': objectLoading}"></div>
                    </td>
                </tr>

                <tr valign="top" class="alternate" v-if="action.task == 'subscribe'">
                    <td scope="row-title">
                        <label for="tablecell">
                            <?php esc_attr_e( 'Update Existing Record', 'advanced-form-integration' ); ?>
                        </label>
                    </td>
                    <td>
                        <input type="checkbox" name="fieldData[update]" value="true" v-model="fielddata.update">
                    </td>
                </tr>

                <tr valign="top" class="alternate" v-if="action.task == 'subscribe'">
                    <td scope="row-title">
                        <label for="tablecell">
                            <?php esc_attr_e( 'Matching Attribute', 'advanced-form-integration' ); ?>
                        </label>
                    </td>
                    <td>
                        <input class="regular-text" type="text" name="fieldData[match]" v-model="fielddata.match">
                        <p class="description"><?php esc_attr_e( 'Only required for updating existing records. Example: domains, email_addresses, name.', 'advanced-form-integration' ); ?></p>
                    </td>
                </tr>


                <editable-field v-for='field in fields' v-bind:key='field.value' v-bind:field='field' v-bind:trigger='trigger' v-bind:action='action' v-bind:fielddata='fielddata'></editable-field>

                <?php adfoin_pro_feature_notice( 'subscribe', 'Attio CRM [PRO]', 'additional objects' ); ?>
            </table>
        </script>
    <?php
}

/*
 * Attio API Request
 */
function adfoin_attio_request( $endpoint, $method = 'GET', $data = [], $record = [], $cred_id = '' ) {

    $credentials = adfoin_get_credentials_by_id( 'attio', $cred_id );
    $access_token = isset( $credentials['accessToken'] ) ? $credentials['accessToken'] : '';
    $base_url = 'https://api.attio.com/v2/';
    $url      = $base_url . $endpoint;

    $args = [
        'timeout' => 30,
        'method'  => $method,
        'headers' => [
            'Content-Type' => 'application/json',
            'Authorization' => 'Bearer ' . $access_token,
        ],
    ];

    if ('POST' == $method || 'PUT' == $method || 'PATCH' == $method) {
        $args['body'] = wp_json_encode($data);
    }

    $response = wp_remote_request($url, $args);

    // Attio rate-limits write requests (25/s) and returns HTTP 429 with a
    // Retry-After header (a date). The request was NOT processed, so it is
    // safe to retry once after waiting for the reset (clamped to <=30s).
    if ( 429 == (int) wp_remote_retrieve_response_code( $response ) ) {
        $retry_after = wp_remote_retrieve_header( $response, 'retry-after' );
        $wait        = 2;

        if ( $retry_after ) {
            if ( is_numeric( $retry_after ) ) {
                $wait = (int) $retry_after;
            } else {
                $reset_ts = strtotime( $retry_after );
                if ( $reset_ts ) {
                    $wait = $reset_ts - time();
                }
            }
        }

        if ( $wait < 1 ) {
            $wait = 1;
        }
        if ( $wait > 30 ) {
            $wait = 30;
        }

        sleep( $wait );
        $response = wp_remote_request( $url, $args );
    }

    if ($record) {
        adfoin_add_to_log($response, $url, $args, $record);
    }

    return $response;
}

add_action( 'wp_ajax_adfoin_get_attio_credentials', 'adfoin_get_attio_credentials', 10, 0 );
/*
 * Get Attio credentials (masked list for action dropdowns).
 */
function adfoin_get_attio_credentials() {
    if ( ! class_exists( 'ADFOIN_Account_Manager' ) ) {
        require_once plugin_dir_path( __FILE__ ) . '../../includes/class-adfoin-account-manager.php';
    }
    ADFOIN_Account_Manager::ajax_get_credentials_list( 'attio' );
}

add_action( 'wp_ajax_adfoin_save_attio_credentials', 'adfoin_save_attio_credentials', 10, 0 );
/*
 * Save (or delete) a single Attio account row.
 */
function adfoin_save_attio_credentials() {
    if ( ! class_exists( 'ADFOIN_Account_Manager' ) ) {
        require_once plugin_dir_path( __FILE__ ) . '../../includes/class-adfoin-account-manager.php';
    }
    ADFOIN_Account_Manager::ajax_save_credentials( 'attio', array( 'accessToken' => 'token' ) );
}

add_action( 'wp_ajax_adfoin_get_attio_object_fields', 'adfoin_get_attio_object_fields', 10, 0 );
/*
 * Get Attio object fields
 */
function adfoin_get_attio_object_fields() {
    adfoin_verify_nonce();

    $cred_id   = isset( $_POST['credId'] ) ? sanitize_text_field( wp_unslash( $_POST['credId'] ) ) : '';
    $object_id = isset( $_POST['objectId'] ) ? sanitize_text_field( wp_unslash( $_POST['objectId'] ) ) : '';
    $data      = adfoin_attio_request( "objects/{$object_id}/attributes", 'GET', [], [], $cred_id );

    if( is_wp_error( $data ) ) {
        wp_send_json_error();
    }

    $response_body = json_decode( wp_remote_retrieve_body( $data ), true );
    $skip = [ 'team', 'categories', 'associated_deals' ];
    $fields = [];

    if ( !empty( $response_body['data'] ) && is_array( $response_body['data'] ) ) {
        foreach ( $response_body['data'] as $single ){
            if( true == $single['is_writable'] && !in_array( $single['api_slug'], $skip ) ) {
                $prefix = ( true == $single['is_multiselect'] ) ? 'multi' : 'single';

                // For personal-name field, show both original and split fields for backward compatibility
                if( 'personal-name' == $single['type'] && 'name' == $single['api_slug'] ) {
                    // Original field for backward compatibility
                    array_push( $fields, [ 
                        'key' => $prefix . '__' . $single['type'] . '__' . $single['api_slug'], 
                        'value' => $single['title'] . ' (auto-split)', 
                        'description' => 'Full name will be automatically split into first and last name' 
                    ] );
                    // New separate fields
                    array_push( $fields, [ 
                        'key' => $prefix . '__' . $single['type'] . '__' . $single['api_slug'] . '_first', 
                        'value' => 'First Name', 
                        'description' => 'Recommended' 
                    ] );
                    array_push( $fields, [ 
                        'key' => $prefix . '__' . $single['type'] . '__' . $single['api_slug'] . '_last', 
                        'value' => 'Last Name', 
                        'description' => 'Recommended' 
                    ] );
                } else {
                    array_push( $fields, [ 'key' => $prefix . '__' . $single['type'] . '__' . $single['api_slug'], 'value' => $single['title'], 'description' => '' ] );
                }
            }
        }
    } else {
        wp_send_json_error();
    }

    wp_send_json_success( $fields );
}

add_action( 'wp_ajax_adfoin_get_attio_objects', 'adfoin_get_attio_objects', 10, 0 );
/*
 * Get Attio onjects
 */
function adfoin_get_attio_objects() {
    adfoin_verify_nonce();

    $cred_id       = isset( $_POST['credId'] ) ? sanitize_text_field( wp_unslash( $_POST['credId'] ) ) : '';
    $response      = adfoin_attio_request( 'objects', 'GET', [], [], $cred_id );
    $response_body = json_decode( wp_remote_retrieve_body( $response ), true );

    if ( empty( $response_body ) ) {
        wp_send_json_error();
    }

    if ( !empty( $response_body['data'] ) && is_array( $response_body['data'] ) ) {

        $allowed_list = [ 'companies', 'people', 'deals' ];
        
        $objects = [];
        foreach ( $response_body['data'] as $single ){

            if( in_array( $single['api_slug'], $allowed_list ) ) {
                $objects[$single['api_slug']] = $single['plural_noun'];
            }
        }
   
        wp_send_json_success( $objects );
    } else {
        wp_send_json_error();
    }
}

add_action( 'adfoin_attio_job_queue', 'adfoin_attio_job_queue', 10, 1 );
/*
 * Attio Job Queue
 */
function adfoin_attio_job_queue( $data ) {
    adfoin_attio_send_data( $data['record'], $data['posted_data'] );
}

/*
 * Handles sending data to attio API
 */
function adfoin_attio_send_data( $record, $posted_data ) {

    $record_data    = json_decode( $record['data'], true );

    if ( isset( $record_data['action_data']['cl'] ) && adfoin_check_conditional_logic( $record_data['action_data']['cl'], $posted_data ) ) return;

    // Suppress a duplicate fire of the same submission (form auto-save, a
    // double-clicked submit, or a hook firing twice). Attio "create" always
    // inserts a new record, so without this a double-fire makes duplicates.
    if ( adfoin_attio_is_duplicate_submission( $record, $posted_data ) ) {
        return;
    }

    $data        = $record_data['field_data'];
    $object_id   = isset( $data['objectId'] ) ? $data['objectId'] : '';
    $cred_id     = isset( $data['credId'] ) ? $data['credId'] : '';
    $task        = $record['task'];
    $update      = isset( $data['update'] ) ? $data['update'] : '';
    $matching_attribute = isset( $data['match'] ) ? $data['match'] : '';

    unset( $data['objectId'] );
    unset( $data['credId'] );
    unset( $data['update'] );
    unset( $data['match'] );

    if( $task == 'subscribe' ) {
        $request_data = [];
        $skip = [ 'team', 'categories', 'associated_deals' ];
        $name_data = [ 'first_name' => '', 'last_name' => '' ];

        foreach( $data as $key => $value ) {
            $parts = explode( '__', $key );

            // Mapped field keys are "prefix__type__slug"; skip anything that
            // doesn't split into at least three parts to avoid notices.
            if( count( $parts ) < 3 ) {
                continue;
            }

            list( $is_single, $type, $field ) = $parts;

            if( in_array( $field, $skip ) ) {
                continue;
            }

            $parsed_value = adfoin_get_parsed_values( $value, $posted_data );

            // Normalize date / timestamp values to the ISO format Attio expects.
            if( 'date' == $type || 'timestamp' == $type ) {
                $parsed_value = adfoin_attio_format_date_value( $type, $parsed_value );
            }

            if( 'record-reference' == $type && ( 'company' == $field || 'associated_company' == $field ) ) {
                $parsed_value = adfoin_attio_search_record( 'companies', $parsed_value, $cred_id );
            }

            if( 'record-reference' == $type && ( 'people' == $field || 'associated_people' == $field ) ) {
                $parsed_value = adfoin_attio_search_record( 'people', $parsed_value, $cred_id );
            }

            // Handle old single name field (auto-split for backward compatibility)
            if( 'personal-name' == $type && 'name' == $field && $parsed_value ) {
                $parsed_value = adfoin_attio_parse_name( $parsed_value );
            }

            // Handle separate first and last name fields
            if( 'personal-name' == $type && 'name_first' == $field && $parsed_value ) {
                $name_data['first_name'] = $parsed_value;
                continue;
            }

            if( 'personal-name' == $type && 'name_last' == $field && $parsed_value ) {
                $name_data['last_name'] = $parsed_value;
                continue;
            }

            if( $parsed_value ) {
                if( 'single' == $is_single ) {
                    $request_data[$field] = $parsed_value;
                } else {
                    $request_data[$field] = explode( ',', $parsed_value );
                }
            }
        }

        // Combine first and last name if provided
        if( !empty( $name_data['first_name'] ) || !empty( $name_data['last_name'] ) ) {
            $full_name = trim( $name_data['first_name'] . ' ' . $name_data['last_name'] );
            $request_data['name'] = [
                'first_name' => $name_data['first_name'],
                'last_name'  => $name_data['last_name'],
                'full_name'  => $full_name
            ];
        }

        $request_data = [ 'data' => [ 'values' => $request_data ] ];

        if( $update == 'true' ) {
            if( !$matching_attribute ) {
                if( $object_id == 'companies' ) {
                    $matching_attribute = 'domains';
                }
                
                if( $object_id == 'people' ) {
                    $matching_attribute = 'email_addresses';
                }

                if( $object_id == 'deals' ) {
                    $matching_attribute = 'name';
                }
            }

            $return = adfoin_attio_request( "objects/{$object_id}/records?matching_attribute={$matching_attribute}", 'PUT', $request_data, $record, $cred_id );
        } else {
            $return = adfoin_attio_request( "objects/{$object_id}/records", 'POST', $request_data, $record, $cred_id );
        }
    }

    return;
}

/*
 * Parse full name into first and last name for Attio personal-name fields
 */
function adfoin_attio_parse_name( $full_name ) {
    if ( empty( $full_name ) ) {
        return '';
    }

    // Trim and normalize whitespace
    $full_name = trim( preg_replace( '/\s+/', ' ', $full_name ) );
    
    // Split the name into parts
    $name_parts = explode( ' ', $full_name );
    
    if ( count( $name_parts ) === 1 ) {
        // Only one name provided (treat as first name)
        return [
            'first_name' => $name_parts[0],
            'last_name'  => '',
            'full_name'  => $full_name
        ];
    } else {
        // Multiple parts: first part is first name, rest is last name
        $first_name = array_shift( $name_parts );
        $last_name  = implode( ' ', $name_parts );
        
        return [
            'first_name' => $first_name,
            'last_name'  => $last_name,
            'full_name'  => $full_name
        ];
    }
}

/*
 * Idempotency guard for Attio submissions. Returns true when an identical
 * submission for the same integration was seen within the window. Backed by an
 * atomic add_option lock (UNIQUE option_name) so concurrent jobs are handled.
 * Shared by the free and PRO send handlers. Filterable via `adfoin_attio_dedupe`.
 */
function adfoin_attio_is_duplicate_submission( $record, $posted_data ) {
    if ( ! apply_filters( 'adfoin_attio_dedupe', true, $record, $posted_data ) ) {
        return false;
    }

    $id = isset( $record['id'] ) ? (string) $record['id'] : '';
    if ( '' === $id ) {
        return false;
    }

    $key = 'adfoin_attiodup_' . md5( $id . '|' . wp_json_encode( $posted_data ) );
    $now = time();
    $ttl = 120;

    if ( add_option( $key, (string) ( $now + $ttl ), '', 'no' ) ) {
        return false; // first time — not a duplicate
    }

    $expires = (int) get_option( $key, 0 );
    if ( $expires > 0 && $now > $expires ) {
        update_option( $key, (string) ( $now + $ttl ), 'no' );
        return false; // stale lock taken over
    }

    return true; // identical submission within the window
}

/*
 * Normalize a date/timestamp value to the ISO format Attio expects (date =>
 * YYYY-MM-DD, timestamp => ISO 8601). Already-ISO and unparseable values are
 * returned unchanged so a value we can't confidently parse is never corrupted.
 */
function adfoin_attio_format_date_value( $type, $value ) {
    $value = trim( (string) $value );

    if ( '' === $value ) {
        return $value;
    }

    // Already ISO (date or datetime) — leave as-is.
    if ( preg_match( '/^\d{4}-\d{2}-\d{2}/', $value ) ) {
        return $value;
    }

    $ts = strtotime( $value );
    if ( false === $ts ) {
        return $value;
    }

    return ( 'timestamp' === $type ) ? gmdate( 'c', $ts ) : gmdate( 'Y-m-d', $ts );
}

/*
 * Search Record
 */
function adfoin_attio_search_record( $object_id, $term, $cred_id ) {
    $serarch_term = [ 'limit' => 1, 'filter' => [] ];

    if( 'companies' == $object_id ) {
        $serarch_term['filter']['name'] = $term;
    }

    if( 'people' == $object_id ) {
        $serarch_term['filter']['email_addresses'] = $term;
    }

    $result = adfoin_attio_request( "objects/{$object_id}/records/query", 'POST', $serarch_term, [], $cred_id );
    $body = json_decode( wp_remote_retrieve_body( $result ), true );

    if( isset( $body['data'], $body['data'][0], $body['data'][0]['id'], $body['data'][0]['id']['record_id'] )  ) {
        return $body['data'][0]['id']['record_id'];
    } else {
        return false;
    }
}