from abc import ABC, abstractmethod
import json
from AIBridge.exceptions import AIBridgeException, ValidationException
import csv
import io
import xml.etree.ElementTree as ET
import re
import sqlparse
from json import JSONDecodeError
import jsonschema


class Validation(ABC):
    @abstractmethod
    def validate(self, output_string, schema):
        pass


class JsonSchema(Validation):
    def validate(self, output_string, schema=None):
        try:
            if type(output_string) == dict:
                json_data = json.loads(output_string)
            else:
                if "}" not in output_string:
                    output_string += '"}'
                    output_string = output_string + "}"
                json_string = output_string[
                    output_string.index("{") : len(output_string)
                    - output_string[::-1].index("}")
                ]
                json_string = json_string.replace("\n", "")
                json_data = json.loads(json_string)
        except json.JSONDecodeError as e:
            raise AIBridgeException(f" Error in the AI output for the validation->{e}")
        if schema:
            try:
                user_schema = json.loads(schema)
            except AIBridgeException as e:
                raise JSONDecodeError(f"Error in the schema you entred {e}")
            try:
                jsonschema.Draft7Validator.check_schema(user_schema)
                jsonschema.Draft7Validator.check_schema(json_data)
            except jsonschema.exceptions.SchemaError as e:
                raise ValidationException(f"Invalid output JSON schema: {e}")
        return json.dumps(json_data)


class CSVSchema(Validation):
    def validate(self, output_string, schema=None):
        try:
            output_schema=[]
            if schema:
                output_schema=schema.split(",")
                if  not output_schema:
                    output_schema=schema.split(" ")
                if not output_schema:
                    raise ValidationException("CSV Schema is not in proper format ")
            reader = csv.reader(output_string.splitlines(), delimiter=",")
            new_rows=[]
            for row in reader:
                if len(row)>= len(output_schema)-1:
                    new_rows.append(row)
            if not new_rows:
                raise ValidationException("No csv data found in the output")
            rows_with_index = [(str(index), *row) for index, row in enumerate(new_rows)]
            rows_as_strings = [",".join(row) for row in rows_with_index]
            if "," not in output_schema:
                schema = ",".join(output_schema)
            result_text = "\n".join([schema] + rows_as_strings)
            result_text=result_text.replace("|",",")
            return result_text
        except csv.Error as e:
            raise ValidationException(f"{e}")


class SQLSchema(Validation):
    def validate(self, output_string, schema=None):
        sql_keywords = [
            "SELECT",
            "UPDATE",
            "INSERT",
            "DELETE",
            "FROM",
            "WHERE",
            "JOIN",
        ]
        pattern = r"\b(?:{})\b".format("|".join(sql_keywords))
        if re.search(pattern, output_string, re.IGNORECASE):
            parsed = sqlparse.parse(output_string)
            if any(parsed):
                return output_string
            else:
                raise ValidationException(
                    f"Sql schema genrated by AI is not a valid schema"
                )
        else:
            raise ValidationException(
                f"Sql schema genrated by AI is not a valid schema"
            )


class XMLSchema(Validation):
    def validate(self, output_string, schema=None):
        if """<?xml version="1.0" encoding="UTF-8"?>""" in output_string:
            output_string = output_string.replace(
                """<?xml version="1.0" encoding="UTF-8"?>""", ""
            )
        xml_match = re.search(r'```xml(?:.*?<?xml.*?>)?(.*?)```', output_string, re.DOTALL)
        if xml_match:
            output_string = xml_match.group(1)
        try:
            output_schema = ET.fromstring(output_string)
        except ET.ParseError as e:
            raise ValidationException(
                f"Xml schema generated by AI is not a valid schema->{e}"
            )
        if schema:
            input_schema = ET.fromstring(schema)

            def validate_xml(output_schema, input_schema):
                if output_schema.tag != input_schema.tag:
                    return False
                if output_schema.attrib != input_schema.attrib:
                    return False
                for child1, child2 in zip(output_schema, input_schema):
                    if not validate_xml(child1, child2):
                        return False

                return True

            result = validate_xml(output_schema, input_schema)
            if not result:
                raise ValidationException(
                    f"Xml schema generated by AI is not a valid schema"
                )
        if """<?xml version="1.0" encoding="UTF-8"?>""" not in output_string:
            output_string = """<?xml version="1.0" encoding="UTF-8"?>""" +"\n"+ output_string
        return output_string
