<?php
/**
 * CSV Parser using League CSV.
 *
 * @package PrimeLink
 */

namespace PrimeLink\Modules\Imports\Parsers;

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

final class CsvParser {

    /**
     * Parse a CSV file and return structured preview.
     *
     * @param string $file_path Absolute file path.
     * @param array  $args      Preview args (max_rows, delimiter, enclosure, escape, etc).
     * @return array {headers:[], rows:[[]], total:int}
     */
    public function preview( $file_path, $args = array() ) {
        $defaults = array(
            'max_rows'  => 0,    // 0 = unlimited
            'delimiter' => ',',
            'enclosure' => '"',
            'escape'    => '\\',
        );
        $args = wp_parse_args( (array) $args, $defaults );

        if ( ! \PrimeLink\Helpers\FilesystemHelper::file_exists( $file_path ) ) {
            return array(
                'headers' => array(),
                'rows'    => array(),
                'total'   => 0,
                'message' => 'CSV file not readable.',
            );
        }

        // League CSV 9.x requires PHP 8.1.2+
        // If PHP < 8.1.2, use native fallback directly
        if ( version_compare( PHP_VERSION, '8.1.2', '<' ) ) {
            return $this->preview_native( $file_path, $args );
        }

        // Try prefixed League CSV first (production), then normal (development)
        $csv_reader_class = null;
        if ( class_exists( '\PrimeLink\Vendor\League\Csv\Reader' ) ) {
            $csv_reader_class = '\PrimeLink\Vendor\League\Csv\Reader';
        } elseif ( class_exists( '\League\Csv\Reader' ) ) {
            $csv_reader_class = '\League\Csv\Reader';
        }

        if ( $csv_reader_class ) {
            try {
                return $this->preview_with_league_csv( $file_path, $args, $csv_reader_class );
            } catch ( \ParseError $e ) {
                // If parse error (syntax incompatibility), use fallback
                return $this->preview_native( $file_path, $args );
            } catch ( \Exception $e ) {
                // Other errors, use fallback
                return $this->preview_native( $file_path, $args );
            }
        }

        // Fallback to native PHP
        return $this->preview_native( $file_path, $args );
    }

    /**
     * Preview using League CSV.
     *
     * @param string $file_path      File path.
     * @param array  $args           Arguments.
     * @param string $csv_reader_class CSV Reader class name (prefixed or normal).
     * @return array
     */
    private function preview_with_league_csv( $file_path, $args, $csv_reader_class = '\League\Csv\Reader' ) {
        try {
            $reader = $csv_reader_class::createFromPath( $file_path, 'r' );
            
            // Set delimiter
            if ( ! empty( $args['delimiter'] ) ) {
                $reader->setDelimiter( $args['delimiter'] );
            }
            
            // Set enclosure
            if ( ! empty( $args['enclosure'] ) ) {
                $reader->setEnclosure( $args['enclosure'] );
            }
            
            // Set escape
            if ( ! empty( $args['escape'] ) ) {
                $reader->setEscape( $args['escape'] );
            }

            // Delimiter is already set above if provided in args
            // League CSV doesn't have getDelimiterStats() - we use the provided delimiter or default ','

            $max_rows = (int) $args['max_rows'];
            $rows     = array();
            $count    = 0;

            foreach ( $reader as $record ) {
                // Skip empty rows
                if ( empty( $record ) || ( 1 === count( $record ) && '' === trim( (string) $record[0] ) ) ) {
                    continue;
                }

                $rows[] = $record;
                $count++;

                // If max > 0, stop after header + max rows
                if ( $max_rows > 0 && $count >= ( $max_rows + 1 ) ) {
                    break;
                }
            }

            $headers = $rows[0] ?? array();
            $body    = array_slice( $rows, 1 );

            return array(
                'headers' => $headers,
                'rows'    => $body,
                'total'   => count( $body ),
            );
        } catch ( \Exception $e ) {
            // Fallback to native if League CSV fails
            return $this->preview_native( $file_path, $args );
        }
    }

    /**
     * Preview using native PHP (fallback).
     *
     * @param string $file_path File path.
     * @param array  $args      Arguments.
     * @return array
     */
    private function preview_native( $file_path, $args ) {
        $handle = fopen( $file_path, 'r' );
        if ( false === $handle ) {
            return array(
                'headers' => array(),
                'rows'    => array(),
                'total'   => 0,
                'message' => 'CSV file could not be opened.',
            );
        }

        $rows = array();
        $max  = (int) $args['max_rows'];
        $line = 0;

        while ( ( $data = fgetcsv( $handle, 0, $args['delimiter'], $args['enclosure'], $args['escape'] ) ) !== false ) {
            if ( empty( $data ) || ( 1 === count( $data ) && '' === trim( (string) $data[0] ) ) ) {
                continue;
            }

            $rows[] = $data;
            $line++;

            if ( $max > 0 && $line >= ( $max + 1 ) ) {
                break;
            }
        }

        fclose( $handle );

        $headers = $rows[0] ?? array();
        $body    = array_slice( $rows, 1 );

        return array(
            'headers' => $headers,
            'rows'    => $body,
            'total'   => count( $body ),
        );
    }

    /**
     * Parse full CSV into generator/array for real import.
     *
     * @param string $file_path File path.
     * @param array  $args      Arguments.
     * @return \Generator|array
     */
    public function parse( $file_path, $args = array() ) {
        $defaults = array(
            'delimiter' => ',',
            'enclosure' => '"',
            'escape'    => '\\',
        );
        $args = wp_parse_args( (array) $args, $defaults );

        if ( ! \PrimeLink\Helpers\FilesystemHelper::file_exists( $file_path ) ) {
            return array();
        }

        // League CSV 9.x requires PHP 8.1.2+
        // If PHP < 8.1.2, use native fallback directly
        if ( version_compare( PHP_VERSION, '8.1.2', '<' ) ) {
            // Fallback to native PHP - skip to native implementation
            $handle = fopen( $file_path, 'r' );
            if ( false === $handle ) {
                return array();
            }

            // Skip header
            fgetcsv( $handle, 0, $args['delimiter'], $args['enclosure'], $args['escape'] );

            while ( ( $data = fgetcsv( $handle, 0, $args['delimiter'], $args['enclosure'], $args['escape'] ) ) !== false ) {
                if ( ! empty( $data ) && ! ( 1 === count( $data ) && '' === trim( (string) $data[0] ) ) ) {
                    yield $data;
                }
            }
            fclose( $handle );
            return;
        }

        // Try prefixed League CSV first (production), then normal (development)
        $csv_reader_class = null;
        if ( class_exists( '\PrimeLink\Vendor\League\Csv\Reader' ) ) {
            $csv_reader_class = '\PrimeLink\Vendor\League\Csv\Reader';
        } elseif ( class_exists( '\League\Csv\Reader' ) ) {
            $csv_reader_class = '\League\Csv\Reader';
        }

        if ( $csv_reader_class ) {
            try {
                $reader = $csv_reader_class::createFromPath( $file_path, 'r' );
                
                if ( ! empty( $args['delimiter'] ) ) {
                    $reader->setDelimiter( $args['delimiter'] );
                }
                if ( ! empty( $args['enclosure'] ) ) {
                    $reader->setEnclosure( $args['enclosure'] );
                }
                if ( ! empty( $args['escape'] ) ) {
                    $reader->setEscape( $args['escape'] );
                }

                // Return generator for memory efficiency
                foreach ( $reader as $record ) {
                    if ( ! empty( $record ) && ! ( 1 === count( $record ) && '' === trim( (string) $record[0] ) ) ) {
                        yield $record;
                    }
                }
                return;
            } catch ( \ParseError $e ) {
                // If parse error (syntax incompatibility), use fallback
            } catch ( \Exception $e ) {
                // Other errors, use fallback
            }
        }

        // Fallback to native PHP
        $handle = fopen( $file_path, 'r' );
        if ( false === $handle ) {
            return array();
        }

        // Skip header
        fgetcsv( $handle, 0, $args['delimiter'], $args['enclosure'], $args['escape'] );

        while ( ( $data = fgetcsv( $handle, 0, $args['delimiter'], $args['enclosure'], $args['escape'] ) ) !== false ) {
            if ( ! empty( $data ) && ! ( 1 === count( $data ) && '' === trim( (string) $data[0] ) ) ) {
                yield $data;
            }
        }

        fclose( $handle );
    }
}