<?php

namespace App\Services;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class XmlParserService
{
    private $documentId;
    private $sortOrder = 0;

    public function parseAndStore($xmlFilePath, $documentId)
    {
        $this->documentId = $documentId;
        $this->sortOrder = 0;

        try {
            // Load XML file
            $xmlContent = file_get_contents($xmlFilePath);
            $xml = simplexml_load_string($xmlContent);

            if ($xml === false) {
                throw new \Exception('Failed to parse XML file');
            }

            // Start parsing from root
            $this->parseNode($xml, null, 0);

            return ['success' => true, 'message' => 'XML parsed and stored successfully'];
        } catch (\Exception $e) {
            Log::error('XML parsing error: ' . $e->getMessage());
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    private function parseNode($node, $parentId = null, $level = 0)
    {
        $nodeName = strtolower($node->getName());
        
        // Skip certain nodes
        if (in_array($nodeName, ['xml', 'parsererror'])) {
            return null;
        }

        $provisionData = [
            'document_id' => $this->documentId,
            'parent_id' => $parentId,
            'level' => $level,
            'sort_order' => $this->sortOrder++,
            'element_type' => $nodeName,
            'element_id' => null,
            'label' => null,
            'heading' => null,
            'marginal_note' => null,
            'content' => null,
            'attributes' => json_encode($this->getAttributes($node)),
            'created_at' => now(),
            'updated_at' => now()
        ];

        // Extract element ID from attributes (number, id, etc.)
        $attributes = $node->attributes();
        if (isset($attributes['number'])) {
            $provisionData['element_id'] = (string)$attributes['number'];
        } elseif (isset($attributes['id'])) {
            $provisionData['element_id'] = (string)$attributes['id'];
        }

        // Extract label
        if (isset($attributes['label'])) {
            $provisionData['label'] = (string)$attributes['label'];
        }

        // Handle different element types
        switch ($nodeName) {
            case 'title':
            case 'heading':
            case 'longtitle':
            case 'shorttitle':
                $provisionData['heading'] = $this->getTextContent($node);
                break;

            case 'marginalnote':
            case 'marginal-note':
                $provisionData['marginal_note'] = $this->getTextContent($node);
                break;

            case 'section':
            case 'article':
            case 'clause':
            case 'subsection':
            case 'subclause':
            case 'paragraph':
            case 'subparagraph':
            case 'clause':
            case 'item':
                // Get direct text content (not nested elements)
                $provisionData['content'] = $this->getDirectTextContent($node);
                break;

            case 'definition':
            case 'term':
                $provisionData['content'] = $this->getTextContent($node);
                $provisionData['element_type'] = 'definition';
                break;

            case 'note':
            case 'remark':
            case 'reference':
            case 'citation':
                $provisionData['content'] = $this->getTextContent($node);
                break;

            default:
                // Generic text content
                $textContent = $this->getDirectTextContent($node);
                if (!empty(trim($textContent))) {
                    $provisionData['content'] = $textContent;
                }
                break;
        }

        // Only insert if there's meaningful content
        if ($provisionData['heading'] || $provisionData['content'] || $provisionData['marginal_note']) {
            $provisionId = DB::table('legal_document_provisions')->insertGetId($provisionData);

            // Recursively parse child elements
            foreach ($node->children() as $child) {
                $this->parseNode($child, $provisionId, $level + 1);
            }

            return $provisionId;
        } else {
            // No meaningful content, just parse children without creating a provision
            foreach ($node->children() as $child) {
                $this->parseNode($child, $parentId, $level);
            }
            return $parentId;
        }
    }

    private function getAttributes($node)
    {
        $attributes = [];
        foreach ($node->attributes() as $key => $value) {
            $attributes[$key] = (string)$value;
        }
        return $attributes;
    }

    private function getTextContent($node)
    {
        // Get all text content including from child elements
        $text = '';
        foreach ($node->children() as $child) {
            $text .= $this->getTextContent($child) . ' ';
        }
        
        // Also get direct text
        $directText = trim((string)$node);
        if (!empty($directText)) {
            $text = $directText . ' ' . $text;
        }
        
        return trim($text);
    }

    private function getDirectTextContent($node)
    {
        // Get only direct text content, not from child elements
        $text = trim((string)$node);
        
        // Remove text from child elements
        foreach ($node->children() as $child) {
            $childText = trim((string)$child);
            if (!empty($childText)) {
                $text = str_replace($childText, '', $text);
            }
        }
        
        return trim($text);
    }
}
