import graphviz
import json
from tempfile import NamedTemporaryFile
import os

def generate_entity_relationship_diagram(json_input: str, output_format: str) -> str:
    """
    Generates an Entity Relationship (ER) diagram from JSON input.

    Args:
        json_input (str): A JSON string describing the ER diagram structure.
                          It must follow the Expected JSON Format Example below.

        output_format (str): The output format for the generated diagram.
                            Supported formats: "png" or "svg"

    Expected JSON Format Example:
    {
      "entities": [
        {
          "name": "Person",
          "type": "strong",
          "attributes": [
            {
              "name": "person_id",
              "type": "primary_key"
            },
            {
              "name": "first_name",
              "type": "regular"
            },
            {
              "name": "last_name",
              "type": "regular"
            },
            {
              "name": "birth_date",
              "type": "regular"
            },
            {
              "name": "age",
              "type": "derived"
            },
            {
              "name": "phone_numbers",
              "type": "multivalued"
            },
            {
              "name": "full_address",
              "type": "composite"
            }
          ]
        },
        {
          "name": "Student",
          "type": "strong",
          "attributes": [
            {
              "name": "student_number",
              "type": "regular"
            },
            {
              "name": "enrollment_date",
              "type": "regular"
            },
            {
              "name": "gpa",
              "type": "derived"
            }
          ]
        },
        {
          "name": "UndergraduateStudent",
          "type": "strong",
          "attributes": [
            {
              "name": "major",
              "type": "regular"
            },
            {
              "name": "expected_graduation",
              "type": "regular"
            },
            {
              "name": "credits_completed",
              "type": "regular"
            }
          ]
        },
        {
          "name": "GraduateStudent",
          "type": "strong",
          "attributes": [
            {
              "name": "thesis_topic",
              "type": "regular"
            },
            {
              "name": "advisor_id",
              "type": "regular"
            },
            {
              "name": "degree_type",
              "type": "regular"
            }
          ]
        },
        {
          "name": "Faculty",
          "type": "strong",
          "attributes": [
            {
              "name": "employee_number",
              "type": "regular"
            },
            {
              "name": "hire_date",
              "type": "regular"
            },
            {
              "name": "office_number",
              "type": "regular"
            },
            {
              "name": "years_of_service",
              "type": "derived"
            }
          ]
        },
        {
          "name": "Professor",
          "type": "strong",
          "attributes": [
            {
              "name": "rank",
              "type": "regular"
            },
            {
              "name": "tenure_status",
              "type": "regular"
            },
            {
              "name": "research_areas",
              "type": "multivalued"
            }
          ]
        },
        {
          "name": "Lecturer",
          "type": "strong",
          "attributes": [
            {
              "name": "contract_type",
              "type": "regular"
            },
            {
              "name": "courses_per_semester",
              "type": "regular"
            }
          ]
        },
        {
          "name": "Staff",
          "type": "strong",
          "attributes": [
            {
              "name": "position_title",
              "type": "regular"
            },
            {
              "name": "department_assigned",
              "type": "regular"
            },
            {
              "name": "salary_grade",
              "type": "regular"
            }
          ]
        },
        {
          "name": "AdministrativeStaff",
          "type": "strong",
          "attributes": [
            {
              "name": "access_level",
              "type": "regular"
            },
            {
              "name": "responsibilities",
              "type": "multivalued"
            }
          ]
        },
        {
          "name": "TechnicalStaff",
          "type": "strong",
          "attributes": [
            {
              "name": "certifications",
              "type": "multivalued"
            },
            {
              "name": "equipment_assigned",
              "type": "multivalued"
            }
          ]
        },
        {
          "name": "Vehicle",
          "type": "strong",
          "attributes": [
            {
              "name": "vehicle_id",
              "type": "primary_key"
            },
            {
              "name": "license_plate",
              "type": "regular"
            },
            {
              "name": "year",
              "type": "regular"
            },
            {
              "name": "current_value",
              "type": "derived"
            }
          ]
        },
        {
          "name": "Car",
          "type": "strong",
          "attributes": [
            {
              "name": "doors",
              "type": "regular"
            },
            {
              "name": "fuel_type",
              "type": "regular"
            }
          ]
        },
        {
          "name": "Bus",
          "type": "strong",
          "attributes": [
            {
              "name": "capacity",
              "type": "regular"
            },
            {
              "name": "route_assigned",
              "type": "regular"
            }
          ]
        },
        {
          "name": "MaintenanceVehicle",
          "type": "strong",
          "attributes": [
            {
              "name": "equipment_type",
              "type": "regular"
            },
            {
              "name": "specialized_tools",
              "type": "multivalued"
            }
          ]
        },
        {
          "name": "Course",
          "type": "strong",
          "attributes": [
            {
              "name": "course_id",
              "type": "primary_key"
            },
            {
              "name": "course_name",
              "type": "regular"
            },
            {
              "name": "credits",
              "type": "regular"
            }
          ]
        },
        {
          "name": "Department",
          "type": "strong",
          "attributes": [
            {
              "name": "dept_id",
              "type": "primary_key"
            },
            {
              "name": "dept_name",
              "type": "regular"
            },
            {
              "name": "budget",
              "type": "regular"
            }
          ]
        }
      ],
      "relationships": [
        {
          "name": "PersonISA",
          "type": "isa",
          "parent": "Person",
          "children": ["Student", "Faculty", "Staff"]
        },
        {
          "name": "StudentISA",
          "type": "isa",
          "parent": "Student",
          "children": ["UndergraduateStudent", "GraduateStudent"]
        },
        {
          "name": "FacultyISA",
          "type": "isa",
          "parent": "Faculty",
          "children": ["Professor", "Lecturer"]
        },
        {
          "name": "StaffISA",
          "type": "isa",
          "parent": "Staff",
          "children": ["AdministrativeStaff", "TechnicalStaff"]
        },
        {
          "name": "VehicleISA",
          "type": "isa",
          "parent": "Vehicle",
          "children": ["Car", "Bus", "MaintenanceVehicle"]
        },
        {
          "name": "Enrolls",
          "type": "regular",
          "entities": ["Student", "Course"],
          "cardinalities": {
            "Student": "M",
            "Course": "M"
          },
          "attributes": [
            {
              "name": "semester"
            },
            {
              "name": "year"
            },
            {
              "name": "grade"
            }
          ]
        },
        {
          "name": "Teaches",
          "type": "regular",
          "entities": ["Faculty", "Course"],
          "cardinalities": {
            "Faculty": "M",
            "Course": "M"
          },
          "attributes": [
            {
              "name": "semester"
            },
            {
              "name": "classroom"
            }
          ]
        },
        {
          "name": "WorksIn",
          "type": "regular",
          "entities": ["Faculty", "Department"],
          "cardinalities": {
            "Faculty": "M",
            "Department": "1"
          },
          "attributes": [
            {
              "name": "start_date"
            }
          ]
        },
        {
          "name": "Manages",
          "type": "regular",
          "entities": ["Staff", "Department"],
          "cardinalities": {
            "Staff": "M",
            "Department": "M"
          },
          "attributes": [
            {
              "name": "role"
            }
          ]
        },
        {
          "name": "Uses",
          "type": "regular",
          "entities": ["Staff", "Vehicle"],
          "cardinalities": {
            "Staff": "M",
            "Vehicle": "M"
          },
          "attributes": [
            {
              "name": "usage_date"
            },
            {
              "name": "purpose"
            }
          ]
        }
      ]
    }

    Returns:
        str: The filepath to the generated image file.
    """
    try:
        if not json_input.strip():
            return "Error: Empty input"
            
        data = json.loads(json_input)
        
        if 'entities' not in data:
            raise ValueError("Missing required field: entities")

        dot = graphviz.Graph(comment='ER Diagram', engine='neato')
        dot.attr(
            bgcolor='white',
            pad='1.5',
            overlap='false',
            splines='true',
            sep='+25',
            esep='+15'
        )
        dot.attr('node', fontname='Arial', fontsize='10', color='#404040')
        dot.attr('edge', fontname='Arial', fontsize='9', color='#4a4a4a')
        
        entity_color = '#BEBEBE'
        attribute_color = '#B8D4F1'
        relationship_color = '#FFF9C4'
        isa_color = '#A8E6CF'
        
        font_color = 'black'
        
        entities = data.get('entities', [])
        relationships = data.get('relationships', [])
        
        for entity in entities:
            entity_name = entity.get('name')
            entity_type = entity.get('type', 'strong')
            attributes = entity.get('attributes', [])
            
            if not entity_name:
                continue
            
            entity_color = '#BEBEBE'
            
            if entity_type == 'weak':
                dot.node(
                    entity_name, 
                    entity_name, 
                    shape='box', 
                    style='filled,rounded',
                    fillcolor=entity_color,
                    fontcolor=font_color,
                    color='#404040',
                    penwidth='3',
                    width='1.8',
                    height='0.8',
                    fontsize='12'
                )
            else:
                dot.node(
                    entity_name, 
                    entity_name, 
                    shape='box', 
                    style='filled,rounded',
                    fillcolor=entity_color,
                    fontcolor=font_color,
                    color='#404040',
                    penwidth='1',
                    width='1.8',
                    height='0.8',
                    fontsize='12'
                )
            
            for i, attr in enumerate(attributes):
                attr_name = attr.get('name', '')
                attr_type = attr.get('type', 'regular')
                
                attr_id = f"{entity_name}_attr_{i}"
                attr_color = attribute_color
                
                if attr_type == 'primary_key':
                    dot.node(
                        attr_id, 
                        f'{attr_name} (PK)', 
                        shape='ellipse', 
                        style='filled,rounded',
                        fillcolor=attr_color,
                        fontcolor=font_color,
                        color='#404040',
                        width='1.2',
                        height='0.6',
                        fontsize='10'
                    )
                elif attr_type == 'partial_key':
                    dot.node(
                        attr_id, 
                        f'{attr_name} (Partial)', 
                        shape='ellipse', 
                        style='filled,rounded,dashed',
                        fillcolor=attr_color,
                        fontcolor=font_color,
                        color='#404040',
                        width='1.2',
                        height='0.6',
                        fontsize='10'
                    )
                elif attr_type == 'multivalued':
                    dot.node(
                        attr_id, 
                        attr_name, 
                        shape='ellipse', 
                        style='filled,rounded',
                        fillcolor=attr_color,
                        fontcolor=font_color,
                        color='#404040',
                        penwidth='3',
                        width='1.2',
                        height='0.6',
                        fontsize='10'
                    )
                elif attr_type == 'derived':
                    dot.node(
                        attr_id, 
                        f'/{attr_name}/', 
                        shape='ellipse', 
                        style='filled,rounded,dashed',
                        fillcolor=attr_color,
                        fontcolor=font_color,
                        color='#404040',
                        width='1.2',
                        height='0.6',
                        fontsize='10'
                    )
                elif attr_type == 'composite':
                    dot.node(
                        attr_id, 
                        attr_name, 
                        shape='ellipse', 
                        style='filled,rounded',
                        fillcolor=attr_color,
                        fontcolor=font_color,
                        color='#404040',
                        width='1.2',
                        height='0.6',
                        fontsize='10'
                    )
                else:
                    dot.node(
                        attr_id, 
                        attr_name, 
                        shape='ellipse', 
                        style='filled,rounded',
                        fillcolor=attr_color,
                        fontcolor=font_color,
                        color='#404040',
                        width='1.2',
                        height='0.6',
                        fontsize='10'
                    )
                
                dot.edge(entity_name, attr_id, color='#4a4a4a', len='1.5')
        
        for relationship in relationships:
            rel_name = relationship.get('name')
            rel_type = relationship.get('type', 'regular')
            entities_involved = relationship.get('entities', [])
            cardinalities = relationship.get('cardinalities', {})
            rel_attributes = relationship.get('attributes', [])
            
            if not rel_name:
                continue
            
            if rel_type == 'isa':
                parent = relationship.get('parent')
                children = relationship.get('children', [])
                
                if parent and children:
                    isa_id = f"isa_{rel_name}"
                    isa_color = isa_color
                    
                    dot.node(
                        isa_id, 
                        'ISA', 
                        shape='triangle', 
                        style='filled,rounded',
                        fillcolor=isa_color,
                        fontcolor=font_color,
                        color='#404040',
                        penwidth='2',
                        width='1.0',
                        height='0.8',
                        fontsize='10'
                    )
                    
                    dot.edge(parent, isa_id, color='#4a4a4a', len='2.0')
                    
                    for child in children:
                        dot.edge(isa_id, child, color='#4a4a4a', len='2.0')
                
            elif len(entities_involved) >= 2:
                rel_color = relationship_color
                
                if rel_type == 'identifying':
                    dot.node(
                        rel_name, 
                        rel_name, 
                        shape='diamond', 
                        style='filled,rounded',
                        fillcolor=rel_color,
                        fontcolor=font_color,
                        color='#404040',
                        penwidth='3',
                        width='1.8',
                        height='1.0',
                        fontsize='11'
                    )
                else:
                    dot.node(
                        rel_name, 
                        rel_name, 
                        shape='diamond', 
                        style='filled,rounded',
                        fillcolor=rel_color,
                        fontcolor=font_color,
                        color='#404040',
                        penwidth='1',
                        width='1.8',
                        height='1.0',
                        fontsize='11'
                    )
                
                for j, attr in enumerate(rel_attributes):
                    attr_name = attr.get('name', '')
                    attr_id = f"{rel_name}_attr_{j}"
                    attr_color = attribute_color
                    
                    dot.node(
                        attr_id, 
                        attr_name, 
                        shape='ellipse', 
                        style='filled,rounded',
                        fillcolor=attr_color,
                        fontcolor=font_color,
                        color='#404040',
                        width='1.0',
                        height='0.5',
                        fontsize='9'
                    )
                    dot.edge(rel_name, attr_id, color='#4a4a4a', len='1.0')
                
                for entity in entities_involved:
                    cardinality = cardinalities.get(entity, '1')
                    dot.edge(
                        entity, 
                        rel_name, 
                        label=f' {cardinality} ',
                        color='#4a4a4a',
                        len='2.5',
                        fontcolor='#4a4a4a',
                        fontsize='10'
                    )

        with NamedTemporaryFile(delete=False, suffix=f'.{output_format}') as tmp:
            dot.render(tmp.name, format=output_format, cleanup=True)
            return f"{tmp.name}.{output_format}"

    except json.JSONDecodeError:
        return "Error: Invalid JSON format"
    except Exception as e:
        return f"Error: {str(e)}"