<?php

namespace Devikit\Fakturowo\Api;

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

/**
 * Fakturowo API Client
 * 
 * Dokumentacja (API v1 - podstawowe funkcje): /pomoc/api-podstawowe-funkcje
 *
 * API zwraca dane tekstowe (linie oddzielone \n).
 * - Dla większości zadań: 1 = sukces, 0 = błąd.
 * - Druga linia przy błędzie: opis błędu.
 * - Wyjątek: api_zadanie=8 zwraca liczbę (kolejny numer dokumentu) lub 0.
 */
class Client {

    /**
     * API Key (api_id)
     * 
     * @var string
     */
    private $api_key;

    /**
     * API URL (różny dla każdego konta, np. https://firma123.fakturowo.pl/api/)
     * 
     * @var string
     */
    private $api_url;

    /**
     * Constructor
     * 
     * @param string $api_key API ID from Fakturowo
     * @param string $api_url Custom API URL for this account
     */
    public function __construct( $api_key, $api_url = '' ) {
        $this->api_key = $api_key;
        $this->api_url = ! empty( $api_url ) ? rtrim( $api_url, '/' ) : '';
    }

    /**
     * Test connection (verbose)
     * 
     * @return true|\WP_Error
     */
    public function test_connection_verbose() {
        if ( empty( $this->api_url ) || empty( $this->api_key ) ) {
            return new \WP_Error( 'fakturowo_api_missing_credentials', __( 'Missing API URL or API Key.', 'invoicing-integration-for-fakturowo-and-woocommerce' ) );
        }

        // Najbezpieczniejszy "ping" wg dokumentacji v1:
        // api_zadanie=8 (pobranie kolejnego numeru dokumentu) – nie wymaga produktów.
        $result = $this->get_next_document_number( 0 );
        if ( is_wp_error( $result ) ) {
            $this->log( 'Test connection failed (api_zadanie=8): ' . $result->get_error_message(), 'error' );
            return $result;
        }

        $this->log( 'Test connection successful (api_zadanie=8)', 'info' );
        return true;
    }

    /**
     * Test connection (bool wrapper)
     *
     * @return bool
     */
    public function test_connection() {
        return ! is_wp_error( $this->test_connection_verbose() );
    }

    /**
     * Get next document number (api_zadanie=8)
     *
     * @param int $document_type Dokument rodzaj (np. 0 = Faktura VAT, 2 = Proforma).
     * @return int|\WP_Error
     */
    public function get_next_document_number( $document_type = 0 ) {
        $lines = $this->request_lines( [
            'api_zadanie'      => '8',
            'dokument_rodzaj'  => (string) (int) $document_type,
        ] );

        if ( is_wp_error( $lines ) ) {
            return $lines;
        }

        $value = isset( $lines[0] ) ? (int) $lines[0] : 0;
        if ( $value > 0 ) {
            return $value;
        }

        return new \WP_Error( 'fakturowo_api_error', __( 'API returned invalid next document number.', 'invoicing-integration-for-fakturowo-and-woocommerce' ) );
    }

    /**
     * Create invoice/proforma (api_zadanie=1)
     *
     * @param array $data Normalized data:
     *  - document_type (int) 0=VAT, 2=Proforma
     *  - buyer (array) nabywca_* fields
     *  - items (array[]) each: name, qty, jm, vat, gross
     *  - document_access (0|1) dokument_dostep
     *  - dates (array) document_date_w, document_date_s in DD-MM-YYYY
     * @return array|\WP_Error { api_numer, download_url?, preview_url?, filename? }
     */
    public function create_invoice( $data ) {
        $document_type   = isset( $data['document_type'] ) ? (int) $data['document_type'] : 0;
        $document_access = isset( $data['document_access'] ) ? (int) $data['document_access'] : 0;
        $buyer           = isset( $data['buyer'] ) && is_array( $data['buyer'] ) ? $data['buyer'] : [];
        $items           = isset( $data['items'] ) && is_array( $data['items'] ) ? $data['items'] : [];

        if ( empty( $items ) ) {
            return new \WP_Error( 'fakturowo_api_error', __( 'Missing invoice items (products).', 'invoicing-integration-for-fakturowo-and-woocommerce' ) );
        }

        $params = [
            'api_zadanie'      => '1',
            'dokument_rodzaj'  => (string) $document_type,
            'dokument_dostep'  => (string) $document_access,
        ];

        // Allow passing any dokument_* / sprzedawca_* parameters directly (optional).
        foreach ( $data as $key => $value ) {
            $key = (string) $key;
            if ( strpos( $key, 'dokument_' ) === 0 || strpos( $key, 'sprzedawca_' ) === 0 ) {
                $params[ $key ] = (string) $value;
            }
        }

        if ( ! empty( $data['document_date_w'] ) ) {
            $params['dokument_data_w'] = (string) $data['document_date_w'];
        }
        if ( ! empty( $data['document_date_s'] ) ) {
            $params['dokument_data_s'] = (string) $data['document_date_s'];
        }

        // Buyer (nabywca_*).
        foreach ( $buyer as $key => $value ) {
            $key = (string) $key;
            if ( strpos( $key, 'nabywca_' ) !== 0 ) {
                continue;
            }
            $params[ $key ] = (string) $value;
        }

        // Items => produkt_*_1..N
        $i = 1;
        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) {
                continue;
            }
            $name  = isset( $item['name'] ) ? (string) $item['name'] : '';
            $qty   = isset( $item['qty'] ) ? (string) $item['qty'] : '1';
            $jm    = isset( $item['jm'] ) ? (string) $item['jm'] : '2'; // 2 = szt.
            $vat   = isset( $item['vat'] ) ? (string) $item['vat'] : '23';
            $gross = isset( $item['gross'] ) ? (string) $item['gross'] : '';

            if ( $name === '' || $gross === '' ) {
                continue;
            }

            $params[ 'produkt_nazwa_' . $i ]          = $name;
            $params[ 'produkt_ilosc_' . $i ]          = $qty;
            $params[ 'produkt_jm_' . $i ]             = $jm;
            $params[ 'produkt_stawka_vat_' . $i ]     = $vat;
            $params[ 'produkt_wartosc_brutto_' . $i ] = $gross;

            $i++;
            if ( $i > 100 ) {
                break;
            }
        }

        $lines = $this->request_lines( $params );
        if ( is_wp_error( $lines ) ) {
            return $lines;
        }

        // Success response for api_zadanie=1:
        // 1\napi_numer\n[download_url]\n[preview_url]\n[filename]
        if ( ! isset( $lines[0] ) || $lines[0] !== '1' ) {
            $msg = isset( $lines[1] ) ? $lines[1] : __( 'Unknown API error.', 'invoicing-integration-for-fakturowo-and-woocommerce' );
            return new \WP_Error( 'fakturowo_api_error', $msg );
        }

        $result = [
            'api_numer' => isset( $lines[1] ) ? $lines[1] : '',
        ];
        if ( isset( $lines[2] ) ) {
            $result['download_url'] = $lines[2];
        }
        if ( isset( $lines[3] ) ) {
            $result['preview_url'] = $lines[3];
        }
        if ( isset( $lines[4] ) ) {
            $result['filename'] = $lines[4];
        }

        return $result;
    }

    /**
     * Get document details (api_zadanie=3 with specific api_numer)
     * Returns document number, dates, etc.
     *
     * @param string|int $api_numer Document ID from Fakturowo
     * @return array|\WP_Error { dokument_numer, dokument_rodzaj, dokument_data_w, ... }
     */
    public function get_document_details( $api_numer ) {
        if ( empty( $this->api_key ) || empty( $this->api_url ) ) {
            return new \WP_Error( 'no_api_credentials', 'API credentials are required' );
        }

        $params = [
            'api_zadanie' => '3',
            'api_numer'   => (string) $api_numer,
            'p'           => '1',
        ];

        $lines = $this->request_lines( $params );
        if ( is_wp_error( $lines ) ) {
            return $lines;
        }

        // Response format for api_zadanie=3:
        // Line 0: 1 (success) or 0 (error)
        // Line 1: total pages count
        // Line 2+: document data in CSV format:
        // api_numer;dokument_rodzaj;dokument_numer;dokument_data_w;dokument_data_s;dokument_waluta;wartość netto;wartość vat;wartość brutto;sprzedawca_nazwa;adres sprzedawcy;sprzedawca_nip;nabywca_nazwa;adres nabywcy;nabywca_nip;dokument_status;dokument_zaplata;dokument_termin;

        if ( ! isset( $lines[0] ) || $lines[0] !== '1' ) {
            $msg = isset( $lines[1] ) ? $lines[1] : __( 'Failed to get document details.', 'invoicing-integration-for-fakturowo-and-woocommerce' );
            return new \WP_Error( 'fakturowo_api_error', $msg );
        }

        // Document data is in line 2
        if ( ! isset( $lines[2] ) ) {
            return new \WP_Error( 'fakturowo_api_error', __( 'Document not found.', 'invoicing-integration-for-fakturowo-and-woocommerce' ) );
        }

        $data = explode( ';', $lines[2] );
        
        // Parse document data according to API documentation
        $result = [
            'api_numer'         => isset( $data[0] ) ? $data[0] : '',
            'dokument_rodzaj'   => isset( $data[1] ) ? $data[1] : '',
            'dokument_numer'    => isset( $data[2] ) ? $data[2] : '',
            'dokument_data_w'   => isset( $data[3] ) ? $data[3] : '',
            'dokument_data_s'   => isset( $data[4] ) ? $data[4] : '',
            'dokument_waluta'   => isset( $data[5] ) ? $data[5] : '',
            'wartosc_netto'     => isset( $data[6] ) ? $data[6] : '',
            'wartosc_vat'       => isset( $data[7] ) ? $data[7] : '',
            'wartosc_brutto'    => isset( $data[8] ) ? $data[8] : '',
            'sprzedawca_nazwa'  => isset( $data[9] ) ? $data[9] : '',
            'adres_sprzedawcy'  => isset( $data[10] ) ? $data[10] : '',
            'sprzedawca_nip'    => isset( $data[11] ) ? $data[11] : '',
            'nabywca_nazwa'     => isset( $data[12] ) ? $data[12] : '',
            'adres_nabywcy'     => isset( $data[13] ) ? $data[13] : '',
            'nabywca_nip'       => isset( $data[14] ) ? $data[14] : '',
            'dokument_status'   => isset( $data[15] ) ? $data[15] : '',
            'dokument_zaplata'  => isset( $data[16] ) ? $data[16] : '',
            'dokument_termin'   => isset( $data[17] ) ? $data[17] : '',
        ];

        $this->log( 'Document details retrieved: ' . wp_json_encode( $result, JSON_UNESCAPED_UNICODE ), 'debug' );

        return $result;
    }

    /**
     * Download Invoice PDF (GET /pobierz?api_id&api_numer)
     *
     * @param string|int $api_numer
     * @return string|\WP_Error
     */
    public function download_invoice_pdf( $api_numer ) {
        if ( empty( $this->api_key ) || empty( $this->api_url ) ) {
            return new \WP_Error( 'no_api_credentials', 'API credentials are required' );
        }

        $base = $this->get_account_base_url();
        if ( is_wp_error( $base ) ) {
            return $base;
        }

        $url = add_query_arg(
            [
                'api_id'    => $this->api_key,
                'api_numer' => (string) $api_numer,
            ],
            $base . '/pobierz'
        );

        $response = wp_safe_remote_get(
            $url,
            [
                'timeout' => 30,
            ]
        );

        if ( is_wp_error( $response ) ) {
            return $response;
        }

        $code = wp_remote_retrieve_response_code( $response );
        
        if ( $code !== 200 ) {
            $body = wp_remote_retrieve_body( $response );
            return new \WP_Error( 'pdf_download_failed', 'Failed to download PDF: ' . $body );
        }

        $body = wp_remote_retrieve_body( $response );
        
        // Check if it's actually PDF (starts with %PDF)
        if ( substr( $body, 0, 4 ) !== '%PDF' ) {
            // It's an error message (TXT).
            return new \WP_Error( 'pdf_download_failed', 'PDF download error: ' . $body );
        }

        return $body;
    }

    /**
     * Get bank accounts (API v1 nie ma listy rachunków przez api_zadanie)
     *
     * @param bool $refresh
     * @return array Always empty for API v1
     */
    public function get_bank_accounts( $refresh = false ) {
        return [];
    }

    /**
     * Get VAT Rates
     * 
     * @param bool $refresh Force refresh from API
     * @return array
     */
    public function get_vat_rates( $refresh = false ) {
        // Fakturowo doesn't have API for VAT rates, return standard Polish rates
        return [
            '23' => '23%',
            '8'  => '8%',
            '5'  => '5%',
            '0'  => '0%',
            'zw' => 'zw',
            'np' => 'np',
        ];
    }

    /**
     * Clear API cache
     */
    public static function clear_cache() {
        delete_transient( 'devikit_fakturowo_bank_accounts' );
    }

    /**
     * Send request to Fakturowo API
     * 
     * @param array $params Request parameters
     * @return string|WP_Error Response body or error
     */
    private function request_lines( $params ) {
        if ( empty( $this->api_url ) ) {
            $error = new \WP_Error( 'no_api_url', 'API URL is not configured. Please set it in settings.' );
            $this->log( 'Error: API URL not configured' );
            return $error;
        }

        if ( empty( $this->api_key ) ) {
            $error = new \WP_Error( 'no_api_key', 'API Key is not configured.' );
            $this->log( 'Error: API Key not configured' );
            return $error;
        }

        // Required: api_id + api_zadanie.
        $params['api_id'] = $this->api_key;
        if ( empty( $params['api_zadanie'] ) ) {
            return new \WP_Error( 'fakturowo_api_error', __( 'Missing api_zadanie.', 'invoicing-integration-for-fakturowo-and-woocommerce' ) );
        }

        // Use POST method (recommended by Fakturowo).
        $response = wp_safe_remote_post( $this->api_url, [
            'body' => $params,
            'timeout' => 30,
        ] );

        if ( is_wp_error( $response ) ) {
            $this->log( 'Request Error: ' . $response->get_error_message() );
            return $response;
        }

        $code = wp_remote_retrieve_response_code( $response );
        $body = wp_remote_retrieve_body( $response );
        $content_type = wp_remote_retrieve_header( $response, 'content-type' );

        if ( $code !== 200 ) {
            $this->log( "API Error ($code): Request failed" );
            return new \WP_Error( 'fakturowo_api_error', 'API request failed with code ' . $code, [ 'code' => $code ] );
        }

        // Wrong API URL often returns an HTML page (sometimes with HTTP 200).
        // Detect it ONLY if body clearly starts with full HTML document structure.
        // (Fakturowo may return text/html header even for valid text responses, so we ignore content-type.)
        $body_trim = ltrim( (string) $body );
        if ( $body_trim !== '' && strlen( $body_trim ) > 100 ) {
            $prefix = strtolower( substr( $body_trim, 0, 200 ) );
            // Only flag as HTML if we see actual DOCTYPE or opening <html> tag.
            if ( strpos( $prefix, '<!doctype html' ) !== false || preg_match( '/<html\s/i', $prefix ) ) {
                $this->log(
                    'Invalid API response (HTML detected). Body prefix: ' . substr( $body_trim, 0, 120 ),
                    'error'
                );
                return new \WP_Error(
                    'fakturowo_api_invalid_url',
                    __( 'Invalid API response (HTML). The API URL is probably incorrect and does not point to the Fakturowo API endpoint. Please verify the API URL in your Fakturowo account (Konto → Parametry API).', 'invoicing-integration-for-fakturowo-and-woocommerce' )
                );
            }
        }

        $raw_lines = preg_split( "/\r\n|\r|\n/", (string) $body );
        $lines     = [];
        foreach ( $raw_lines as $line ) {
            $line = trim( $line );
            if ( $line === '' ) {
                continue;
            }
            $lines[] = $line;
        }

        // api_zadanie=8 zwraca liczbę w 1. linii (lub 0).
        if ( (string) $params['api_zadanie'] === '8' ) {
            if ( isset( $lines[0] ) && (int) $lines[0] > 0 ) {
                return $lines;
            }
            $msg = isset( $lines[1] ) ? $lines[1] : __( 'API error.', 'invoicing-integration-for-fakturowo-and-woocommerce' );
            return new \WP_Error( 'fakturowo_api_error', $msg, [ 'code' => 0 ] );
        }

        // Standard: 1 = success, 0 = error.
        if ( isset( $lines[0] ) && $lines[0] === '1' ) {
            return $lines;
        }

        $msg = isset( $lines[1] ) ? $lines[1] : __( 'API error.', 'invoicing-integration-for-fakturowo-and-woocommerce' );
        return new \WP_Error( 'fakturowo_api_error', $msg, [ 'code' => isset( $lines[0] ) ? $lines[0] : 0 ] );
    }

    /**
     * Get base URL for current account (scheme://host)
     *
     * @return string|\WP_Error
     */
    private function get_account_base_url() {
        $parts = wp_parse_url( $this->api_url );
        if ( empty( $parts['scheme'] ) || empty( $parts['host'] ) ) {
            return new \WP_Error( 'fakturowo_api_error', __( 'Invalid API URL.', 'invoicing-integration-for-fakturowo-and-woocommerce' ) );
        }
        return $parts['scheme'] . '://' . $parts['host'];
    }

    /**
     * Log message
     * 
     * @param string $message
     * @param string $level Log level: 'error', 'warning', 'info', 'debug'
     */
    public function log( $message, $level = 'error' ) {
        if ( ! class_exists( 'WC_Logger' ) ) {
            return;
        }

        $logger = wc_get_logger();
        
        // Check if debug logging is enabled
        $settings = get_option( 'devikit_fakturowo_settings', [] );
        $debug_enabled = isset( $settings['enable_debug_logging'] ) && $settings['enable_debug_logging'] === 'yes';
        
        if ( $debug_enabled ) {
            // Log to debug file when enabled
            $logger->log( $level, $message, [ 'source' => 'devikit_fakturowo_debug' ] );
        } elseif ( $level === 'error' ) {
            // Always log errors to main file
            $logger->error( $message, [ 'source' => 'invoicing-integration-for-fakturowo-and-woocommerce' ] );
        }
    }
}
