import math
from flask import Flask, render_template, request, jsonify, redirect, url_for
import json
import random
from datetime import datetime, timedelta

app = Flask(__name__)

# Funciones originales de cálculo de parques eólicos y almacenamiento de datos

def obtener_generadores_fila(numero_objetos):
    lado_x = math.ceil(math.sqrt(numero_objetos / 3))
    lado_y = math.ceil(numero_objetos / lado_x)
    return lado_x, lado_y

def marca_aerogenerador(potencia_generador, diametro_generador):
    if potencia_generador == 2.0 and diametro_generador == 80.0:
        return "VESTAS V80-2.0 MW"
    elif potencia_generador == 2.0 and diametro_generador == 90.0:
        return "VESTAS V90-3.0 MW"
    elif potencia_generador == 4.2 and diametro_generador == 117.0:
        return "VESTAS V117-4.2 MW"
    elif potencia_generador == 8.0 and diametro_generador == 164.0:
        return "VESTAS V164-8.0 MW"
    elif potencia_generador == 8.0 and diametro_generador == 167.0:
        return "SIEMENS GAMESA SG 8.0-167 DD"
    elif potencia_generador == 10.0 and diametro_generador == 164.0:
        return "VESTAS V164-10.0 MW"
    elif potencia_generador == 11.0 and diametro_generador == 200.0:
        return "SIEMENS GAMESA SG 11.0-200 DD"
    elif potencia_generador == 14.0 and diametro_generador == 222.0:
        return "SIEMENS GAMESA SG 14.0-222 DD"
    elif potencia_generador == 14.0 and diametro_generador == 236.0:
        return "SIEMENS GAMESA SG 14.0-236 DD"
    elif potencia_generador == 15.0 and diametro_generador == 236.0:
        return "VESTAS V236-15.0 MW"
    else:
        return "No definido"

def calcular_cantidad_generadores(potencia_parque, potencia_generador):
    return math.ceil(potencia_parque / potencia_generador)


def calcular_area_parque(cantidad_generadores, diametro_generador):
    distancia_fila = 4 * diametro_generador
    distancia_entre_filas = 8 * diametro_generador
    lado_x, lado_y = obtener_generadores_fila(cantidad_generadores)  # Obtener las dimensiones del rectángulo
    area_parque = ((lado_y * diametro_generador) + ((lado_y - 1) * distancia_fila)) * ((lado_x - 1) * distancia_entre_filas)
    return round(area_parque / (1000 * 1000), 2) # Dar el resultado en kilometros cuadrados y redondear a 2 el numero maximo de decimales 


def determinar_tipo_cimentacion(profundidad_agua):
    if profundidad_agua < 25:
        return 'Gravedad'
    elif 25 <= profundidad_agua < 30:
        return 'Monopilote'
    elif 30 <= profundidad_agua < 40:
        return 'Tripilote'
    elif 40 <= profundidad_agua <= 80:
        return 'Tripode o Jacket'
    else:
        return 'Mástil, pierna tensora o semisumergible'


def determinar_tipo_transmision(distancia_costa, potencia_parque):
    if distancia_costa <= 99:
        if potencia_parque <= 400:
            return 'HVAC'
        elif 400 < potencia_parque <= 900:
            return 'HVDC o HVAC'
        elif 600 <= potencia_parque <= 1000:
            return 'HVDC o HVAC'
    else:
        if potencia_parque <= 900:
            return 'HVDC'
        elif 600 <= potencia_parque <= 2000:
            return 'HVDC'
    return 'HVAC o HVDC'
  
def obtener_ultimo_id(existing_data):
    if existing_data:
        used_ids = [int(id) for id in existing_data.keys()]
        available_ids = [id for id in range(10000) if id not in used_ids]
        if available_ids:
            return random.choice(available_ids)
        else:
            return max(used_ids) + 1
    else:
        return random.randint(0, 9999)


# Nuevas funciones para organizar objetos

def organizar_objetos(numero_objetos):
    imagen_presente = 'X'  # Representa la presencia de la imagen
    lado_x_1 = math.ceil(math.sqrt(numero_objetos / 3))
    lado_y_1 = math.ceil(numero_objetos / lado_x_1)
    objetos_opcion_1 = lado_x_1 * lado_y_1
    rectangulo_1 = [[' ' for _ in range(lado_x_1)] for _ in range(lado_y_1)]
    for i in range(numero_objetos):
        row = i // lado_x_1
        col = i % lado_x_1
        rectangulo_1[row][col] = imagen_presente

    return {
        "opcion_1": {
            "lado_x": lado_x_1,
            "lado_y": lado_y_1,
            "numero_ajustado": min(numero_objetos, objetos_opcion_1),
            "rectangulo": rectangulo_1
        }
    }

def calcular_datos(data):
    potencia_parque = data['potenciaParque']

    potencia_generador = data['potenciaGenerador']    
    cantidad_generadores = math.ceil(potencia_parque / potencia_generador)

    return {
        "cantidadGeneradores": cantidad_generadores,
    }

#Calcular cables de interconexion y cable de exportacion
def calcular_cables_interconexion(potencia_aerogenerador, numero_generadores):
    if potencia_aerogenerador == 2:
        if numero_generadores == 5:
            return "26/35KV 3x70"
    elif potencia_aerogenerador == 3:
        if numero_generadores == 5:
            return "26/35KV 3x95"
        elif numero_generadores == 10:
            return "66KV 3x95"
    elif potencia_aerogenerador == 4.2:
        if numero_generadores == 5:
            return "26/35KV 3x150"
        elif numero_generadores == 10:
            return "66KV 3x150"
    elif potencia_aerogenerador == 8:
        if numero_generadores == 5:
            return "26/35KV 3x500"
        elif numero_generadores == 7:
            return "66KV 3x300"
        elif numero_generadores == 10:
            return "66KV 3x500"
    elif potencia_aerogenerador == 10:
        if numero_generadores == 4:
            return "26/35KV 3x500"
        elif numero_generadores == 7:
            return "66KV 3x500"
    elif potencia_aerogenerador == 11:
        if numero_generadores == 7:
            return "66KV 3x630"
    elif potencia_aerogenerador == 14:
        if numero_generadores == 6:
            return "66KV 3x800"
    elif potencia_aerogenerador == 15:
        if numero_generadores == 6:
            return "66KV 3x1000"
    
    return "No definido"


def calcular_cable_exportacionAC(potencia_parque, tipo_transmision, distancia_costa):
    if distancia_costa <= 99 and tipo_transmision in ['HVAC', 'HVAC o HVDC', 'HVDC o HVAC']:
        if 200 <= potencia_parque <= 275:
            return "300KV 3x300 mm²"
        elif 275 < potencia_parque <= 300:
            return "300KV 3x400 mm²"
        elif 300 < potencia_parque <= 340:
            return "300KV 3x500 mm²"
        elif 340 < potencia_parque <= 370:
            return "300KV 3x630 mm²"
        elif 370 < potencia_parque <= 400:
            return "300KV 3x800 mm²"
        elif 400 < potencia_parque <= 430:
            return "300KV 3x1000 mm²"
        elif 430 < potencia_parque <= 600:
            return "2 cables de 300KV 3x400 mm²"
        elif 600 < potencia_parque <= 800:
            return "2 cables de 300KV 3x800 mm²"
        elif 800 < potencia_parque <= 1000:
            return "3 cables de 300KV 3x500 mm²"
        elif 1000 < potencia_parque <= 1200:
            return "3 cables de 300KV 3x800 mm²"
        elif 1200 < potencia_parque <= 1400:
            return "4 cables de 300KV 3x630 mm²"
        elif 1400 < potencia_parque <= 1600:
            return "4 cables de 300KV 3x800 mm²"
        else:
            return "No definido"
    else:
        return "Es necesario que use cable DC"


def calcular_cable_exportacionDC(potencia_parque, tipo_transmision):
    if tipo_transmision in ['HVDC', 'HVAC o HVDC', 'HVDC o HVAC']:
        if 150 <= potencia_parque <= 225:
            return "1 cable DC 200 KV de 240 mm²"
        elif 225 < potencia_parque <= 250:
            return "1 cable DC 200 KV de 300 mm²"
        elif 250 < potencia_parque <= 295:
            return "1 cable DC 200 KV de 400 mm²"
        elif 295 < potencia_parque <= 330:
            return "1 cable DC 200 KV de 500 mm²"
        elif 330 < potencia_parque <= 390:
            return "1 cable DC 200 KV de 630 mm²"
        elif 390 < potencia_parque <= 440:
            return "1 cable DC 200 KV de 800 mm²"
        elif 440 < potencia_parque <= 510:
            return "1 cable DC 200 KV de 1000 mm²"
        elif 510 < potencia_parque <= 555:
            return "1 cable DC 200 KV de 1200 mm²"
        elif 555 < potencia_parque <= 600:
            return "1 cable DC 200 KV de 1400 mm²"
        elif 600 < potencia_parque <= 645:
            return "1 cable DC 200 KV de 1600 mm²"
        elif 645 < potencia_parque <= 770:
            return "1 cable DC 420 KV de 630 mm²"
        elif 770 < potencia_parque <= 850:
            return "1 cable DC 420 KV de 800 mm²"
        elif 850 < potencia_parque <= 940:
            return "1 cable DC 420 KV de 1000 mm²"
        elif 940 < potencia_parque <= 1054:
            return "1 cable DC 420 KV de 1200 mm²"
        elif 1054 < potencia_parque <= 1164:
            return "1 cable DC 420 KV de 1400 mm²"
        elif 1164 < potencia_parque <= 1236:
            return "1 cable DC 420 KV de 1600 mm²"
        elif 1236 < potencia_parque <= 1418:
            return "1 cable DC 420 KV de 2000 mm²"
        elif 1418 < potencia_parque <= 1513:
            return "1 cable DC 420 KV de 2200 mm²"
        elif 1513 < potencia_parque <= 1636:
            return "1 cable DC 420 KV de 2500 mm²"
        else:
            return "No definido"
    else:
        return "No definido"


@app.route('/guardar_resultado/', methods=['POST'])
def guardar_resultado():
    try:
        # Obtener los datos del formulario
        nombre_proyecto = request.form['nombreProyecto']
        potencia_parque = float(request.form['potenciaParque'])
        distancia_costa = float(request.form['distanciaCosta'])
        profundidad_agua = float(request.form['profundidadAgua'])
        potencia_generador = float(request.form['potenciaGenerador'])
        
        diametro_generador = float(request.form['diametroGenerador'])
        cantidad_generadores = calcular_cantidad_generadores(potencia_parque, potencia_generador)
        area_parque = calcular_area_parque(cantidad_generadores, diametro_generador)
        tipo_cimentacion = determinar_tipo_cimentacion(profundidad_agua)
        tipo_transmision = determinar_tipo_transmision(distancia_costa, potencia_parque)
        cable_exportacionAC = calcular_cable_exportacionAC(potencia_parque, tipo_transmision, distancia_costa)
        cable_exportacionDC = calcular_cable_exportacionDC(potencia_parque, tipo_transmision)
        marca_aero = marca_aerogenerador(potencia_generador, diametro_generador) 
      
        # Calcular cables de interconexión
        cable_interconexion4 = calcular_cables_interconexion(potencia_generador, 4)
        cable_interconexion5 = calcular_cables_interconexion(potencia_generador, 5)
        cable_interconexion6 = calcular_cables_interconexion(potencia_generador, 6)
        cable_interconexion7 = calcular_cables_interconexion(potencia_generador, 7)
        cable_interconexion10 = calcular_cables_interconexion(potencia_generador, 10)

        
        # Generar el nuevo ID para el proyecto
        with open('data.json', 'r+') as json_file:
            existing_data = json.load(json_file)
            nuevo_id = obtener_ultimo_id(existing_data)
            data = {
                "id": nuevo_id,
                "fecha_hora": (datetime.now() - timedelta(hours=5)).strftime('%d/%m/%Y %H:%M'),
                "nombreProyecto": nombre_proyecto,
                "potenciaParque": potencia_parque,
                "distanciaCosta": distancia_costa,
                "profundidadAgua": profundidad_agua,
                "potenciaGenerador": potencia_generador,
                "marcaAerogenerador": marca_aero,
                "diametroGenerador": diametro_generador,
                "cantidadGeneradores": cantidad_generadores,
                "areaParque": area_parque,
                "tipoCimentacion": tipo_cimentacion,
                "tipoTransmision": tipo_transmision,
                "cableInterconexion4": cable_interconexion4,
                "cableInterconexion5": cable_interconexion5,
                "cableInterconexion6": cable_interconexion6,
                "cableInterconexion7": cable_interconexion7,
                "cableInterconexion10": cable_interconexion10,
                "cableExportacionAC": cable_exportacionAC,
                "cableExportacionDC": cable_exportacionDC,
            }
            
            existing_data[str(nuevo_id)] = data
            json_file.seek(0)
            json.dump(existing_data, json_file, indent=4)

        return redirect(url_for('mostrar_registro', id=data["id"]))
    except Exception as e:
        return jsonify({'error': str(e)}), 500



@app.route('/single_item/')
def mostrar_lista_registros():
    try:
        with open('data.json', 'r') as json_file:
            registros = json.load(json_file)
            return render_template('single_item.html', registros=registros)
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/mostrar_registro/<int:id>/', methods=['GET'])
def mostrar_registro(id):
    try:
        with open('data.json', 'r') as json_file:
            data = json.load(json_file)
            registro = data.get(str(id))
            if registro:
                data_calculados = calcular_datos(registro)
                registro.update(data_calculados)
                diametro_aerogenerador = request.args.get('diametroAerogenerador')  # Obtener el diámetro del aerogenerador desde la solicitud
                registro['diametroAerogenerador'] = diametro_aerogenerador  # Agregar el diámetro del aerogenerador al registro
                return render_template('mostrar_registro.html', registro=registro)
            else:
                return jsonify({'error': 'No se encontró ningún registro con el ID especificado'}), 404
    except (FileNotFoundError, ValueError) as e:
        return jsonify({'error': str(e)}), 500
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# Ruta para mostrar pagina de calculo principañ
@app.route('/')
def index():
    return render_template('prueba1.html')

# Ruta para mostrar la distribucion grafica sugerida
@app.route('/resultado', methods=['POST'])
def resultado():
    numero_objetos = int(request.form['numero_objetos'])
    resultados = organizar_objetos(numero_objetos)
    return render_template('resultado.html', resultados=resultados)

# Ruta para mostrar la pagina principal
@app.route('/prueba1/')
def pagina_prueba():
    return render_template('prueba1.html')

# Ruta para mostrar los registro anteriormente realizados
@app.route('/single_item.html')
def mostrar_registros_antiguos():
    return redirect(url_for('mostrar_lista_registros'))

#Ruta para mostrar informe
@app.route('/mostrar_informe/<int:id>/', methods=['GET'])
def mostrar_informe(id):
    try:
        with open('data.json', 'r') as json_file:
            data = json.load(json_file)
            registro = data.get(str(id))
            if registro:
                data_calculados = calcular_datos(registro)
                registro.update(data_calculados)
                
                # Llamar a organizar_objetos para obtener resultados
                resultados = organizar_objetos(int(registro['cantidadGeneradores']))
                
                return render_template('informe.html', registro=registro, resultados=resultados)
            else:
                return jsonify({'error': 'No se encontró ningún registro con el ID especificado'}), 404
    except (FileNotFoundError, ValueError) as e:
        return jsonify({'error': str(e)}), 500
    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=8000)