use dotenvy::dotenv;
use std::env;
use xml_builder::{XMLBuilder, XMLElement, XMLVersion};
use super::database as db;
use super::database::{DidTargetType, Did};

pub fn url(did: Did) -> XMLElement {
    let mut work = XMLElement::new("work");
    let mut bridge = XMLElement::new("execute");
    let target = did.target.unwrap();

    bridge.add_attribute("application", "bridge");
    bridge.add_attribute("data", format!("sofia/external/{}", target).as_str());

    work.add_child(bridge).unwrap();

    work
}

pub fn moh(_did: Did) -> XMLElement {
    let mut work = XMLElement::new("work");

    let mut playback = XMLElement::new("playback");
    playback.add_attribute("file", "local_stream://default");
    work.add_child(playback).unwrap();

    work
}

pub fn external_number(did: Did) -> XMLElement {
    let mut work = XMLElement::new("work");
    let mut bridge = XMLElement::new("execute");
    let callee_number = did.target.unwrap();
    let ds = build_dial_string(&callee_number, &did.did_number);

    bridge.add_attribute("application", "bridge");
    bridge.add_attribute("data", &ds);

    work.add_child(bridge).unwrap();

    work
}

pub fn no_service(_did: Did) -> XMLElement {
    dotenv().ok();
    let sound_path = env::var("SOUND_PATH").expect("SOUND_PATH must be set");
    let no_service_path = format!("{}/no_service.wav", sound_path);
    let mut work = XMLElement::new("work");

    add_playback_element(&mut work, &no_service_path);

    work
}

pub fn night_mode(_did: Did) -> XMLElement {
    dotenv().ok();
    let sound_path = env::var("SOUND_PATH").expect("SOUND_PATH must be set");
    let night_mode_path = format!("{}/night_mode.wav", sound_path);

    let mut work = XMLElement::new("work");

    add_playback_element(&mut work, &night_mode_path);

    work
}

pub fn custom_message(_did: Did) -> XMLElement {
    let work = XMLElement::new("work");
    work
}

fn build_dial_string(callee_number: &str, caller_number: &str) -> String {
    let ds = match db::get_did_by(&caller_number) {
        Ok(d) => {
            if d.trunk == "3229" || d.trunk == "3401" {
                format!("{{origination_caller_id_number={} }}sofia/gateway/powernet_1/{}",
                        caller_number,
                        callee_number)
            } else {
                format!("{{origination_caller_id_number={} }}sofia/gateway/powernet_2/{}",
                        caller_number,
                        callee_number)
            }
        },
        Err(..) =>{
            format!("{{origination_caller_id_number={} }}sofia/gateway/powernet_1/{}",
                    caller_number,
                    callee_number)
        }
    };

    ds
}

pub fn outbound(did: &str, caller_number: &str) -> XMLElement {
    let mut work = XMLElement::new("work");
    let mut bridge = XMLElement::new("execute");
    let ds = build_dial_string(did, caller_number);

    bridge.add_attribute("application", "bridge");
    bridge.add_attribute("data", &ds);

    work.add_child(bridge).unwrap();

    work
}

pub fn add_playback_element(work: &mut XMLElement ,file_path: &str) {
    let mut answer = XMLElement::new("execute");
    answer.add_attribute("application", "answer");
    work.add_child(answer).unwrap();

    let mut playback = XMLElement::new("playback");
    playback.add_attribute("file", &file_path);
    work.add_child(playback).unwrap();
}

pub fn build_work_element(did: &str, caller_number: &str, caller_ipaddr: &str) -> XMLElement {
    if db::from_pbx(&caller_ipaddr).unwrap() == true {
        outbound(did, caller_number)
    } else {
        let d = db::get_did_by(&did).unwrap();
        let work = match d.target_type {
            DidTargetType::Url => {
                url(d)
            },
            DidTargetType::Moh => {
                moh(d)
            },
            DidTargetType::ExternalNumber => {
                external_number(d)
            },
            DidTargetType::NoService => {
                no_service(d)
            },
            DidTargetType::NightMode => {
                night_mode(d)
            },
            DidTargetType::CustomMessage => {
                custom_message(d)
            }
        };

        work
    }
}

pub fn route_call(did: String, caller_number: String,caller_ipaddr: String) -> Vec<u8> {
    let mut xml = XMLBuilder::new()
        .version(XMLVersion::XML1_1)
        .encoding("UTF-8".into())
        .build();

    let mut doc = XMLElement::new("document");
    doc.add_attribute("type", "xml/freeswitch-httapi");

    let params = XMLElement::new("params");
    let mut work = build_work_element(&did, &caller_number, &caller_ipaddr);

    let mut hangup = XMLElement::new("execute");
    hangup.add_attribute("application", "hangup");
    work.add_child(hangup).unwrap();

    doc.add_child(params).unwrap();

    let d = db::get_did_by(&did);
    match d {
        Ok(d) => {
            if d.active == true {
                doc.add_child(work).unwrap();
            }
        },
        Err(_) => {
            doc.add_child(work).unwrap();
        }
    }

    xml.set_root_element(doc);

    let mut writer: Vec<u8> = Vec::new();
    xml.generate(&mut writer).unwrap();

    writer
}
