<?php

namespace App\Services\Import;

class OfxParser implements FileParserInterface
{
    protected static array $supportedExtensions = ['ofx', 'qfx'];

    /**
     * Parse OFX file and return all transactions
     */
    public function parse(string $filePath, array $options = []): array
    {
        $content = file_get_contents($filePath);
        
        if ($content === false) {
            throw new \RuntimeException("Could not read file: $filePath");
        }
        
        // Parse bank account info
        $accountInfo = $this->parseAccountInfo($content);
        
        // Parse transactions
        $transactions = $this->parseTransactions($content);
        
        // Formatar como dados tabulares
        $headers = ['DTPOSTED', 'TRNTYPE', 'TRNAMT', 'FITID', 'NAME', 'MEMO'];
        $data = [];
        
        foreach ($transactions as $txn) {
            $data[] = [
                $txn['date'] ?? '',
                $txn['type'] ?? '',
                $txn['amount'] ?? '',
                $txn['fitid'] ?? '',
                $txn['name'] ?? '',
                $txn['memo'] ?? '',
            ];
        }
        
        return [
            'headers' => $headers,
            'data' => $data,
            'total_rows' => count($data),
            'account_info' => $accountInfo,
            'raw_transactions' => $transactions,
        ];
    }

    /**
     * Get headers (OFX has fixed structure)
     */
    public function getHeaders(string $filePath, array $options = []): array
    {
        return ['DTPOSTED', 'TRNTYPE', 'TRNAMT', 'FITID', 'NAME', 'MEMO'];
    }

    /**
     * Get preview data
     */
    public function getPreview(string $filePath, int $rows = 10, array $options = []): array
    {
        $parsed = $this->parse($filePath, $options);
        
        $preview = [];
        $count = 0;
        
        foreach ($parsed['data'] as $row) {
            if ($count >= $rows) {
                break;
            }
            $preview[] = [
                'row_index' => $count,
                'data' => $row,
            ];
            $count++;
        }
        
        return [
            'preview' => $preview,
            'total_rows' => $parsed['total_rows'],
            'columns_count' => count($parsed['headers']),
            'headers' => $parsed['headers'],
            'account_info' => $parsed['account_info'] ?? null,
        ];
    }

    /**
     * Parse account information from OFX
     */
    protected function parseAccountInfo(string $content): array
    {
        $info = [];
        
        // Bank ID
        if (preg_match('/<BANKID>([^<\n]+)/i', $content, $matches)) {
            $info['bank_id'] = trim($matches[1]);
        }
        
        // Account ID
        if (preg_match('/<ACCTID>([^<\n]+)/i', $content, $matches)) {
            $info['account_id'] = trim($matches[1]);
        }
        
        // Account Type
        if (preg_match('/<ACCTTYPE>([^<\n]+)/i', $content, $matches)) {
            $info['account_type'] = trim($matches[1]);
        }
        
        // Currency
        if (preg_match('/<CURDEF>([^<\n]+)/i', $content, $matches)) {
            $info['currency'] = trim($matches[1]);
        }
        
        // Balance
        if (preg_match('/<BALAMT>([^<\n]+)/i', $content, $matches)) {
            $info['balance'] = floatval(trim($matches[1]));
        }
        
        // Balance Date
        if (preg_match('/<DTASOF>([^<\n]+)/i', $content, $matches)) {
            $info['balance_date'] = $this->parseOfxDate(trim($matches[1]));
        }
        
        return $info;
    }

    /**
     * Parse transactions from OFX
     */
    protected function parseTransactions(string $content): array
    {
        $transactions = [];
        
        // Find all STMTTRN blocks
        preg_match_all('/<STMTTRN>(.*?)<\/STMTTRN>/is', $content, $matches);
        
        // Também tentar sem tag de fechamento (OFX SGML)
        if (empty($matches[1])) {
            // Split by STMTTRN tags
            $parts = preg_split('/<STMTTRN>/i', $content);
            array_shift($parts); // Remover parte antes do primeiro STMTTRN
            
            foreach ($parts as $part) {
                // Encontrar fim da transação
                $endPos = stripos($part, '</STMTTRN>');
                if ($endPos !== false) {
                    $part = substr($part, 0, $endPos);
                } else {
                    // Tentar encontrar próximo STMTTRN ou fim de lista
                    $nextPos = stripos($part, '<STMTTRN>');
                    if ($nextPos !== false) {
                        $part = substr($part, 0, $nextPos);
                    }
                    $endListPos = stripos($part, '</BANKTRANLIST>');
                    if ($endListPos !== false) {
                        $part = substr($part, 0, $endListPos);
                    }
                }
                
                $txn = $this->parseTransaction($part);
                if (!empty($txn['amount'])) {
                    $transactions[] = $txn;
                }
            }
        } else {
            foreach ($matches[1] as $block) {
                $txn = $this->parseTransaction($block);
                if (!empty($txn['amount'])) {
                    $transactions[] = $txn;
                }
            }
        }
        
        return $transactions;
    }

    /**
     * Parse a single transaction block
     */
    protected function parseTransaction(string $block): array
    {
        $txn = [];
        
        // Type (CREDIT, DEBIT, etc.)
        if (preg_match('/<TRNTYPE>([^<\n]+)/i', $block, $matches)) {
            $txn['type'] = trim($matches[1]);
        }
        
        // Date Posted
        if (preg_match('/<DTPOSTED>([^<\n]+)/i', $block, $matches)) {
            $txn['date'] = $this->parseOfxDate(trim($matches[1]));
        }
        
        // Amount
        if (preg_match('/<TRNAMT>([^<\n]+)/i', $block, $matches)) {
            $txn['amount'] = floatval(str_replace(',', '.', trim($matches[1])));
        }
        
        // FIT ID (unique identifier)
        if (preg_match('/<FITID>([^<\n]+)/i', $block, $matches)) {
            $txn['fitid'] = trim($matches[1]);
        }
        
        // Name/Payee
        if (preg_match('/<NAME>([^<\n]+)/i', $block, $matches)) {
            $txn['name'] = trim($matches[1]);
        }
        
        // Memo
        if (preg_match('/<MEMO>([^<\n]+)/i', $block, $matches)) {
            $txn['memo'] = trim($matches[1]);
        }
        
        // Check Number
        if (preg_match('/<CHECKNUM>([^<\n]+)/i', $block, $matches)) {
            $txn['check_num'] = trim($matches[1]);
        }
        
        return $txn;
    }

    /**
     * Parse OFX date format (YYYYMMDDHHMMSS)
     */
    protected function parseOfxDate(string $date): string
    {
        // Remove timezone info
        $date = preg_replace('/\[.*\]/', '', $date);
        $date = trim($date);
        
        if (strlen($date) >= 8) {
            $year = substr($date, 0, 4);
            $month = substr($date, 4, 2);
            $day = substr($date, 6, 2);
            return "$day/$month/$year";
        }
        
        return $date;
    }

    /**
     * Check if parser supports the extension
     */
    public static function supports(string $extension): bool
    {
        return in_array(strtolower($extension), self::$supportedExtensions);
    }
}
