'use strict';

// JS is synchronous.
// Execute the code block by order after hoisting
// hoisting: var, function declaration 자동적으로 제일 위로 올라간다.

console.log('1'); // 동기
setTimeout(() => console.log('2'), 1000); // 비동기

console.log('3'); // 동기

// Synchronous callback
function printImmediately(print){ // 함수의 선언은 hoisting 때문에 맨위로 간다.
    print();
}

printImmediately(() => console.log('hello'));  // 동기

// Asynchronous callback
function printWithDelay(print, timeout){  // 함수의 선언은 hoisting 때문에 맨위로 간다.
    setTimeout(print, timeout);
}

printWithDelay(() => console.log('async callback'), 2000); // 비동기

// callback hell example
class UserStorage {
    loginUser(id, password, onSuccess, onError) {
        setTimeout(() => {
            if(
                (id === 'ellie' && password === 'dream') ||
                (id === 'coder' && password === 'academy')
            ) {
                onSuccess(id);
            } else {
                onError(new Error('not found'));
            }
        }, 2000);
    }

    getRoles(user, onSuccess, onError) {
        setTimeout(() => {
            if(user === 'ellie') {
                onSuccess({name: 'ellie', role: 'admin'});
            } else {
                onError(new Error('no access'));
            }
        }, 1000);
    }
}

const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your password');
userStorage.loginUser(
    id, 
    password, 
    (user) => {
        userStorage.getRoles(
            user,
            userWithRole => {
                alert(`Hello ${userWithRole.name}, you have a ${userWithRole.role} role`);
            },
            error => {
                console.log(error);
            }
            );
    }, 
    (error) => {console.log(error)}
    );

    // 문제점
    // callback 함수 안에서 계속 다른것을 호출하면 이게 꼬리에 꼬리를 물게 되면
    // 디버깅이 매우 힘들어진다. 가독성이 매우 떨어진다. 유지보수도 어려워진다.