import math

def terzaghi_factors(phi):
    phiRad = math.radians(phi)
    if phi == 0:
        return {'Nc': 5.7, 'Nq': 1.0, 'Ng': 0}
    
    Nq = math.exp(2 * math.pi * (0.75 - phi / 360) * math.tan(phiRad)) / (2 * math.cos(math.radians(45 + phi/2))**2)
    Nc = (Nq - 1) / math.tan(phiRad)
    Ng = 2 * (Nq + 1) * math.tan(phiRad)
    return {'Nc': Nc, 'Nq': Nq, 'Ng': Ng}

def meyerhof_factors(phi):
    phiRad = math.radians(phi)
    if phi == 0:
         return {'Nc': 5.14, 'Nq': 1.0, 'Ng': 0}
    
    Nq = math.exp(math.pi * math.tan(phiRad)) * math.tan(math.radians(45 + phi/2))**2
    Nc = (Nq - 1) / math.tan(phiRad)
    Ng = 2 * (Nq + 1) * math.tan(phiRad)
    return {'Nc': Nc, 'Nq': Nq, 'Ng': Ng}

def solve_bearing_capacity(inputs):
    try:
        method = inputs.get('method', 'terzaghi')
        shape = inputs.get('shape', 'strip')
        phiV = float(inputs.get('phi', 0))
        cV = float(inputs.get('c', 0))
        gammaV = float(inputs.get('gamma', 0))
        Bv = float(inputs.get('B', 0))
        Lv = float(inputs.get('L', Bv))
        Dfv = float(inputs.get('Df', 0))
        fosV = float(inputs.get('fos', 3))
        gwtV = float(inputs.get('gwt', 999)) if inputs.get('gwt') is not None and inputs.get('gwt') != '' else 999.0

        if Bv == 0 or gammaV == 0:
            return {'error': 'Invalid input parameters'}
        
        factors = terzaghi_factors(phiV) if method == 'terzaghi' else meyerhof_factors(phiV)
        Nc, Nq, Ng = factors['Nc'], factors['Nq'], factors['Ng']

        sc, sq, sg = 1, 1, 1
        if method == 'terzaghi':
            if shape == 'square': 
                sc, sg = 1.3, 0.8
            elif shape == 'circular':
                sc, sg = 1.3, 0.6
            elif shape == 'rectangular':
                sc = 1 + 0.3 * Bv / Lv
                sg = 1 - 0.2 * Bv / Lv
        else:
             # Meyerhof
            if shape == 'square' or shape == 'circular':
                 sc = 1 + 0.2 * Nq / Nc
                 sq, sg = 1, 1
            elif shape == 'rectangular':
                 sc = 1 + 0.2 * (Bv / Lv) * Nq / Nc
                 sq, sg = 1, 1
        
        # Water table correction
        gammaEff = gammaV
        gammaW = 9.81
        if gwtV <= Dfv:
             gammaEff = gammaV - gammaW
        elif gwtV < Dfv + Bv:
             gammaEff = gammaV - gammaW * (1 - (gwtV - Dfv) / Bv)
        
        q = gammaV * Dfv
        qult = cV * Nc * sc + q * Nq * sq + 0.5 * gammaEff * Bv * Ng * sg
        qSafe = qult / fosV
        qNet = (qult - q) / fosV + q
        
        Qsafe = qSafe * Bv
        if shape == 'rectangular': Qsafe *= Lv
        elif shape == 'circular': Qsafe *= math.pi * Bv / 4
        elif shape == 'square': Qsafe *= Bv # strip logic usually per meter but here treating as square side if square

        return {
            'result': {
                'Nc': Nc, 'Nq': Nq, 'Ng': Ng,
                'sc': sc, 'sq': sq, 'sg': sg,
                'q': q, 'qult': qult, 'qSafe': qSafe,
                'qNet': qNet, 'Qsafe': Qsafe,
                'gammaEff': gammaEff, 'fosV': fosV,
                'Bv': Bv, 'Dfv': Dfv
            }
        }
    except Exception as e:
        return {'error': str(e)}
