import {takeLatest} from 'redux-saga';
import {take, call, put, fork, cancel, select, race} from 'redux-saga/effects';
import {message} from 'antd';

export function index(id, api) {
    return function*(query) {
        try {
            const {list, total} = yield call(api, query);
            yield put({
                type: 'FETCH_' + id + '_LIST_SUCCESS',
                items: list,
                total
            });
        } catch (err) {
            console.error(err);
            message.error(err);
            yield put({
                type: 'FETCH_' + id + '_LIST_FAILED',
                err,
            });
        }
    }
}

export function watchIndex(id, api) {
    return function*() {
        while (true) {
            const {query} = yield take('FETCH_' + id + '_LIST');
            yield fork(index(id, api), query);
        }
    };
}

export function show(rid, api) {
    return function*(id) {
        try {
            const item = yield call(api, id);
            yield put({
                type: 'FETCH_' + rid + '_ITEM_SUCCESS',
                item
            });
        } catch (err) {
            console.error(err);
            message.error(err);
            yield put({
                type: 'FETCH_' + rid + '_ITEM_FAILED',
                err
            });
        }
    }
}

export function watchShow(rid, api) {
    return function*() {
        while (true) {
            const {id} = yield take('FETCH_' + rid + '_ITEM');
            yield fork(show(rid, api), id);
        }
    }
}

export function create(id, api) {
    return function*(data) {
        try {
            const item = yield call(api, data);
            yield put({
                type: 'CREATE_' + id + '_ITEM_SUCCESS',
                item: {...data, ...item, dateCreated: Date.now()}
            });
        } catch (err) {
            console.error(err);
            message.error(err);
            yield put({
                type: 'CREATE_' + id + '_ITEM_FAILED',
                err
            });
        }
    }
}

export function watchCreate(id, api) {
    return function*() {
        while (true) {
            const {item} = yield take('CREATE_' + id + '_ITEM');
            yield fork(create(id, api), item);
        }
    }
}

export function update(id, api) {
    return function*(data) {
        try {
            yield call(api, data);
            message.success('修改成功!');
            yield put({
                type: 'UPDATE_' + id + '_ITEM_SUCCESS',
                item: data
            });
        } catch (err) {
            console.error(err);
            message.error(err);
            yield put({
                type: 'UPDATE_' + id + '_ITEM_FAILED',
                err
            });
        }
    }
}

export function watchEdit(id, api) {
    return function*() {
        while (true) {
            yield take('UPDATE_' + id);
            yield put({
                type: 'UPDATE_' + id + '_START'
            });
            const {data} = yield race({
                data: take('UPDATE_' + id + '_ITEM'),
                canceled: take('CANCEL_UPDATE_' + id)
            });

            if (data && data.item) {
                yield fork(update(id, api), data.item);
            } else {
                yield put({
                    type: 'UPDATE_' + id + '_END'
                });
            }
        }
    }
}

export function watchUpdate(id, api) {
    return function*() {
        while (true) {
            const {item} = yield take('UPDATE_' + id + '_ITEM');
            yield fork(update(id, api), item);
        }
    }
}

export function deleteItem(rid, api) {
    return function*(id) {
        try {
            yield call(api, id);
            message.success('删除成功!');
            yield put({
                type: 'DELETE_' + rid + '_ITEM_SUCCESS',
                removed: id,
            });
        } catch (err) {
            console.error(err);
            message.error(err);
            yield put({
                type: 'DELETE_' + rid + '_ITEM_FAILED',
                err
            });
        }
    }
}

export function watchDelete(rid, api) {
    return function*() {
        while (true) {
            const {id} = yield take('DELETE_' + rid + '_ITEM');
            yield fork(deleteItem(rid, api), id);
        }
    }
}

export function invoke(command, api, msg = '') {
    return function*(data) {
        try {
            const result = yield call(api, data);
            message.success(msg + '成功!');
            yield put({
                type: command + '_SUCCESS',
                result,
                data
            });
        } catch (err) {
            console.error(msg, err);
            message.error(err);
            yield put({
                type: command + '_FAILED',
                err,
                data
            });
        }
    }
}

export function watch(command, api, msg = '') {
    return function*() {
        while (true) {
            const {data} = yield take(command);
            yield fork(invoke(command, api, msg), data);
        }
    }
}
