import React, { useEffect, useState, createContext, useContext, useRef, Fragment, useCallback } from 'react';
import Styled from 'styled-components/native';
import { Text } from 'galio-framework';
import IconButton from '~/Components/UIControls/IconButton';
import Button from '../UIControls/Button';
import { StyleSheet, View } from 'react-native';
import produce from 'immer';
import fetchGet from '~/Utils/fetch';
import Icon from '~/Components/UIControls/Icon';
import Theme from '~/Themes';
import CloseIcon from '~/Assets/Svgs/close.svg';
import DetailSvg from '~/Assets/Svgs/detail.svg';
import FileTextSvg from '~/Assets/Svgs/file_text_gray.svg';
import RightArrowSvg from '~/Assets/Svgs/right_arrow.svg';
import PlusSvg from '~/Assets/Svgs/plus.svg';
import AnimatedContainer from '../UIControls/AnimatedContainer';
import { Util } from '~/Utils/utils';
import { usePrevious } from '../Hooks';

const Title = Styled.View`
    flex-direction: row;
    padding-left: 0px;
    padding-right: 0px;
    height: 50px;
    background-color: #f5f5f5;
    align-items: center;
    justify-content: space-between;
`;
const Label = Styled(Text)`
    flex:1;
    margin-left: 11px;
    font-size: 20;
    letter-spacing: -2;
    font-family: ${Theme.Fonts.Medium};
    include-font-padding: false;
`;
const Close = Styled.TouchableOpacity`
    height: 100%;
    padding-right: 0px;
    justify-content: center;
    padding-right: 14px;
`;
const ContentContainer = Styled.ScrollView`
    width: 100%;
    padding: 0px
    padding-top: 0px;
    max-height: ${Util.getScreenHeight()-50};
`;
const SearchButton = Styled(Button)`
    width: 100%;
    padding: 0px;
    margin: 0px;
`;

export const Line = Styled.View`
    flex-direction: row;
    padding: 3px;
    justify-content: space-between;
`;

export const SearchTitle = ({title}) => {
    return (
        <View style={{paddingLeft:5, paddingBottom:5}}>
            <Text style={{fontFamily:Theme.Fonts.Regular, fontSize:17, }}>{title}</Text>
        </View>
    )
}

export const checkFilter = (filterState, name, checked, op = 'eq') => {
    const [filters, setFilters] = filterState;
    setFilters(
        produce(filters, draft => {
            const namelist = typeof name === 'string' ? [name] : name;
            const oplist = typeof op === 'string' ? [op] : op;
            for (let name of namelist) {
                for (let op of oplist) {
                    const key = `${name}_${op}`;
                    if (!draft[key]) draft[key] = { field: name };
                    draft[key].op = checked ? op : false;
                }
            }
        }),
    );
};

export const filterValue = (filterState, name, value, op = 'eq', clear = false) => {
    const [filters, setFilters] = filterState;
    const key = `${name}_${op}`;
    console.log('filters',filters);
    setFilters(
        produce(filters, draft => {
            if(clear) {
                for(let key of Object.keys(draft)) {
                    delete draft[key];
                }
            }
            if (!draft[key]) draft[key] = { field: name };
            draft[key].value = value;
            draft[key].op = op;
        }),
    );
};

const defaultRenderOptions = {
    api: '',
    visible: false,
    children: null,
    loading: false,
    setPage: () => {},
    onSearch: () => {},
};
class ActionProvider {
    constructor() {
        this.RenderComponent = null;
        this.renderOptions = defaultRenderOptions;
    }
    open = (visible=true) => { console.log('not set open listener') };
    setOpenListener = (handler=(visible=true)=>{}) => {
        this.open = handler;
    };

    toggle = () => { console.log('not set toggle listener') };
    setToggleListener = (handler=()=>{}) => {
        this.toggle = handler;
    };

    search = (append=false) => { console.log('not set search listener') };
    setSearchListener = (handler=(append=false)=>{}) => {
        this.search = handler;
    };

    action = (action) => {};
    setActionListener = (handler=(action)=>{}) => {
        this.action = handler;
    };

    providerMounted = () => { console.log('not set provider mounted listener') }
    setProviderMountListener = (handler) => {
        this.providerMounted = handler;
    };

    setRenderComponent = (component) => {
        this.RenderComponent = component;
    };
    setRenderOptions = (options) => {
        this.renderOptions = options;
    };
}
class ActionHolder {
    constructor() {
        this.list = {};
    }
    change = (id, action) => { console.log('not set change listener') };
    setChangeListener = (handler) => {
        this.change = handler;
    };
    refresh = () => { console.log('not set refresh listener') };
    setRefreshListener = (handler) => {
        this.refresh = handler;
    };
    get = (id) => {
        if(typeof this.list[id] === 'undefined') {
            return new ActionProvider();
        }
        return this.list[id];
    };
    remove = (id) => {
        if(typeof this.list[id] !== 'undefined') {
            delete this.list[id];
            this.refresh();
        }
    };
}
const initialActions = { 
    holder: new ActionHolder(),
};
const SearchContext = createContext(initialActions);

export const SearchProvider = ({children}) => {
    const [actions, setActions] = useState(initialActions);
    const [refresh, setRefresh] = useState(0);

    const changeAction = (id, action) => {
        if(typeof actions.holder.list[id] === 'undefined') {
            const newActions = {...actions};
            newActions.holder.list[id] = action;
            setActions(newActions);
            setRefresh(Math.random());
        }
    }
    actions.holder.setChangeListener((id, action) => {
        changeAction(id, action);
    });
    actions.holder.setRefreshListener(() => {
        setRefresh(Math.random());
    });
    
    let actionList = [];
    for(const key in actions.holder.list) {
        const action = actions.holder.list[key];
        actionList.push(action);
    }
    return (
        <SearchContext.Provider value={actions}>
            {children}
            {Object.keys(actions.holder.list).map((key, index) => {
                const action = actions.holder.list[key];
                return (
                    <AnimatedContainer key={'action-'+key} visible={action.renderOptions.visible} animation="slideDown" onRequestClose={() => {
                        if(action.renderOptions.visible) {
                            action.open(false);
                            return true;
                        }
                        return false;
                    }}>
                        <Title>
                            <Icon iconFamily="FontAwesome" iconName="search" size={18} style={{paddingLeft:16}} color="#8f8f8f" />
                            <Label>검색조건</Label>
                            <Close onPress={() => { 
                                console.log('close button clicked!'); 
                                action.open(false);
                            }}><CloseIcon width={27} height={27} /></Close>
                        </Title>
                        <ContentContainer>
                            <View style={{padding:36, paddingTop:22}}>
                                {action.renderOptions.children}
                                <SearchButton loading={action.renderOptions.loading} iconFamily="FontAwesome" iconName="search" color="#0b83e6" onPress={() => {
                                    if(action.renderOptions.api) {
                                        action.renderOptions.setPage('refresh-'+Math.random());
                                        action.renderOptions.onSearch();
                                    } else {
                                        action.renderOptions.onSearch();
                                        action.open(false);
                                    }
                                }}>
                                    SEARCH
                                </SearchButton>
                            </View>
                        </ContentContainer>
                    </AnimatedContainer>
                )
            })}
        </SearchContext.Provider>
    );
}

const emptyCallback = () => {};
export const Search = ({
        id, children, api = "", filters = {}, sort = {field:null, order:null}, page = 1, setPage=()=>{}, limit = 20,
        onStart = emptyCallback, onSuccess = emptyCallback, onFailure = emptyCallback, onSearch=()=>{}, onAction=(action)=>{}, searchOnMount=true, 
        setRefreshing = emptyCallback
}) => {
    if(typeof id === 'undefined') {
        throw Error('Search 컴포넌트의 id 프로퍼티는 필수 입니다. useSearch Hook 혹은 SearchIcon 사용시 Search 컴포넌트의 id 와 동일한 id 를 사용하여야 Open 가능합니다.');
    }
    
    const [loading, setLoading] = useState(false);
    const [visible, setVisible] = useState(false);

    const actions = useContext(SearchContext);
    // mount
    useEffect(() => {
        const newAction = new ActionProvider();
        actions.holder.change(id, newAction);

        console.log('search mount');
    },[]);
    const action = actions.holder.get(id);
    action.setOpenListener((visible=true) => {
        console.log('open - ' + id + ' - ' + visible);
        setVisible(visible);
    });
    action.setToggleListener(() => {
        console.log('toggle - ' + id + ' - ' + !visible);
        setVisible(!visible);
    });
    action.setSearchListener((append=false) => {
        console.log('search - ' + id);
        searchAction(append);
    });
    action.setActionListener((action) => {
        console.log('action - ' +id);
        onAction(action);
    })

    action.setRenderOptions({
        api: api,
        children: children,
        visible: visible,
        loading: loading,
        setPage: setPage,
        onSearch: onSearch,
    });
    actions.holder.refresh();

    // unmount
    useEffect(() => () => {
        action.open(false);
        actions.holder.remove(id);

        console.log('search unmount');
    }, []);

    const getRealPage = () => {
        return typeof page === 'number' ? page : 1;
    };

    const prevApi = usePrevious(api);
    const prevLimit = usePrevious(limit);
    const prevPage = usePrevious(page);

    // change parameters
    useEffect(() => {
        console.log('search mount or change limit or change page - ', page);
        if(!prevApi && !prevLimit && !prevPage) {
            // mount
            if(searchOnMount) {
                searchAction(true);
                onSearch();
            }
        } else if(api) {
            // limit or page or api changed
            if(prevApi != api) {
                console.log('changed api');
                searchAction(true);
            } else if(typeof page === 'number' && page > 1) {
                console.log('changed page');
                searchAction(true);
            } else {
                console.log('changed etc searchAction false');
                searchAction(false);
            }
            onSearch();
        }
    }, [limit, page, api]);

    const searchAction = async (append = false) => {
        if(!loading) {
            console.log('search - page', getRealPage(), append);
            console.log(api);
            onStart();
            setLoading(true);
            setRefreshing(true);
            console.log('filters - ', filters);
            const f = Object.values(filters).filter(x => x.op && typeof x.value !== 'undefined' && x.value != null && x.value !== '');
            console.log(f);
            
            try {
                const result = await fetchGet(api, {
                    page: getRealPage(),
                    limit: limit,
                    conditions: f,
                    sort: sort
                });

                onSuccess(result, append);
                setLoading(false);
                setRefreshing(false);
            } catch(error) {
                onFailure(error);
                setLoading(false);
                setRefreshing(false);
            }
            action.open(false);
        } else {
            console.log('searchAction but loading is true and this request skip.');
        }
    }

    return (
        <Fragment/>
    );
};

export const useSearch = (id) => {
    if(typeof id === 'undefined') {
        throw Error('useSearch Hook의 id 프로퍼티는 필수 입니다. Search 컴포넌트의 id 와 동일한 id 로 입력하세요.');
    }

    const action = useContext(SearchContext).holder.get(id);
    return { open:action.open, toggle:action.toggle, search:action.search, action:action.action }
}

export const SearchIcon = ({id, ...rest}) => {
    if(typeof id === 'undefined') {
        throw Error('SearchIcon 컴포넌트의 id 프로퍼티는 필수 입니다. Search 컴포넌트의 id 와 동일한 id 로 입력하세요.');
    }

    const actions = useContext(SearchContext);
    const action = actions.holder.get(id);

    return (
        <IconButton iconFamily="FontAwesome" iconName="search" style={{ paddingRight:0 }} iconStyle={{ margin:10 }} size={19} onPress={() => action.open(true)} {...rest} />
    )
};

const SearchBoxIconContainer = Styled.View`
    width: 35px;
    height: 31px;
    border-radius: 5px;
    border: 1px solid #b9bac4;
    align-items: center;
    justify-content: center;
    background-color: #fff;
    align-self:center;
`;
export const SearchBoxIcon = ({id, style={}, ...rest}) => {
    if(typeof id === 'undefined') {
        throw Error('SearchIcon 컴포넌트의 id 프로퍼티는 필수 입니다. Search 컴포넌트의 id 와 동일한 id 로 입력하세요.');
    }

    const actions = useContext(SearchContext);
    const action = actions.holder.get(id);

    return (
        <SearchBoxIconContainer style={style}>
            <IconButton iconFamily="FontAwesome" iconName="search" color="#9aa3ac" size={17} onPress={() => action.open()} {...rest} />
        </SearchBoxIconContainer>
    )
}

export const PrimaryButton = ({children, buttonStyle={}, textStyle={}, style={}, onPress=()=>{}}) => {
    return (
        <Button style={style} buttonStyle={{ 
            width:70, height:31, borderRadius:5,
            backgroundColor: '#0b83e6',
            borderWidth: 1, borderColor: '#0b83e6',
            ...buttonStyle
        }} textStyle={{
            color: 'white',
            fontFamily: Theme.Fonts.Regular,
            fontSize: 14,
            lineHeight: 20,
            letterSpacing: -1.4, ...textStyle
        }} onPress={onPress}>{children}</Button>
    )
};

export const DefaultButton = ({children, buttonStyle={}, textStyle={}, style={}, onPress=()=>{}}) => {
    return (
        <Button style={style} buttonStyle={{ 
            width:70, height:31, borderRadius:5,
            backgroundColor: '#ffffff',
            borderWidth: 1, borderColor: '#0b83e6',
            ...buttonStyle
        }} textStyle={{
            color: '#0b83e6',
            fontFamily: Theme.Fonts.Regular,
            fontSize: 14,
            lineHeight: 20,
            letterSpacing: -1.4, ...textStyle
        }} color="white" onPress={onPress}>{children}</Button>
    )
}


const DetailIconContainer = Styled.View`
    width: 48; height: 48; background-color:#f5f5f5;
    border-radius: 24; align-items:center; justify-content:center;
    margin-right: 20px;
`;
const DetailButtonContainer = Styled.TouchableOpacity`
    width: 48; height: 48; background-color:#f5f5f5;
    border-radius: 24; align-items:center; justify-content:center;
    margin-right: 20px;
`;
const FileTextIconContainer = Styled.View`
    width: 48; height: 48; background-color:#f5f5f5;
    border-radius: 24; align-items:center; justify-content:center;    
`;
export const DetailIcon = ({style}) => {
    return (
        <DetailIconContainer style={style}>
            <DetailSvg width={21} height={21} color="black" />
        </DetailIconContainer>
    )
};
export const DetailButton = ({style, onPress=()=>{}}) => {
    return (
        <DetailButtonContainer style={style} onPress={onPress}>
            <DetailSvg width={21} height={21} color="black" />
        </DetailButtonContainer>
    )
};
export const FileTextIcon = ({style}) => {
    return (
        <FileTextIconContainer style={style}>
            <FileTextSvg width={21} height={21} color="black" />
        </FileTextIconContainer>
    )
};



export const IconContainerCircleSmall = Styled.View`
    width: 26; height: 26; background-color:#f5f5f5;
    border-radius: 13; align-items:center; justify-content:center;
`;

export const RightArrow = ({width=8, height=12, color="#b9bac4", style={}}) => {
    return (
        <RightArrowSvg style={{...style}} width={width} height={height} color={color} />
    )
}

const CreateButtonContainer = Styled.TouchableOpacity`
    position: absolute;
    width: 48px;
    height: 48px;
    background-color: #0b83e6;
    border-radius: 24px;
    right: 19;
    bottom: 10;
    align-items: center;
    justify-content: center;
    flex-direction: row;
`;
export const CreateButton = ({style, label='', onPress=()=>{}}) => {
    return (
        <CreateButtonContainer onPress={onPress} style={[style]}>
            <PlusSvg width={20} height={20} />
            {!!label && (
                <Text style={{fontFamily:Theme.Regular,fontSize:18,color:'white',lineHeight:20,marginLeft:5}}>{label}</Text>
            )}
        </CreateButtonContainer>
    )
}

export const ListStyle = StyleSheet.create({
    itemContainer: {
        flexDirection: "row",
        paddingLeft: 15,
        paddingTop: 15,
        paddingBottom: 15,
        backgroundColor: '#fff',
        borderWidth: 0,
        borderBottomWidth: 1,
        borderColor: Theme.COLORS.BORDER,
        alignItems: 'center',
        justifyContent: 'space-between',
    },
    center: {
        alignItems: 'center',
        justifyContent: 'center',
    },
    rounded: {
        borderWidth: 1,
        borderColor:'#0b83e6',
        borderRadius: 14,
        color: '#0b83e6',
        fontFamily: Theme.Fonts.Regular,
        includeFontPadding: false,
        fontSize: 12,
        lineHeight: 26,
        letterSpacing:-1.2,
        textAlign: 'center',
        textAlignVertical: 'center',
        height: 28,
        paddingLeft: 10,
        paddingRight: 10,
    }, 
    circleLarge: {
        borderWidth: 1.5,
        borderColor:'#0b83e6',
        backgroundColor: 'white',
        width: 55,
        height: 55,
        borderRadius: 27.5,
        paddingTop: 6,
        color: '#0b83e6',
        fontFamily: Theme.Fonts.Regular,
        includeFontPadding: false,
        fontSize: 16,
        lineHeight: 18,
        letterSpacing:-1.2,
        textAlign: 'center',
        textAlignVertical: 'center',
    },
    typeRounded: {
        borderWidth: 1,
        borderColor:'#9aa3ac',
        borderRadius: 30,
        color: '#9aa3ac',
        fontFamily: Theme.Fonts.Regular,
        includeFontPadding: false,
        fontSize: 18,
        lineHeight: 18,
        letterSpacing:-1.4,
        textAlign: 'center',
        textAlignVertical: 'center',
        height: 63,
        width:63,
        paddingLeft: 10,
        paddingRight: 10,
    }, 
    fillRoundedSmall: {
        borderRadius: 12,
        color: 'white',
        backgroundColor: '#0b83e6',
        fontFamily: Theme.Fonts.Regular,
        includeFontPadding: false,
        fontSize: 12,
        lineHeight: 22,
        letterSpacing:-1.2,
        textAlign: 'center',
        textAlignVertical: 'center',
        height: 22,
        paddingLeft: 10,
        paddingRight: 10,
        overflow: 'hidden',
    }, 
    fillRounded: {
        borderRadius: 14,
        color: 'white',
        backgroundColor: '#0b83e6',
        fontFamily: Theme.Fonts.Regular,
        includeFontPadding: false,
        fontSize: 12,
        lineHeight: 26,
        letterSpacing:-1.2,
        textAlign: 'center',
        textAlignVertical: 'center',
        height: 28,
        paddingLeft: 10,
        paddingRight: 10,
        overflow: 'hidden',
    }, 
    bigRounded : {
        borderWidth: 1,
        borderColor:'#0b83e6',
        borderRadius: 5,
        color: '#0b83e6',
        fontFamily: Theme.Fonts.Regular,
        includeFontPadding: false,
        fontSize: 16,
        lineHeight: 33,
        letterSpacing:-1.8,
        textAlign: 'center',
        textAlignVertical: 'center',
        height: 35,
        paddingLeft: 10,
        paddingRight: 10,
        paddingBottom:3
    },        
    textMedium: {
        fontSize: 16,
        lineHeight: 24,
        letterSpacing:-1.6,
        color: 'black',
        fontFamily: Theme.Fonts.Medium,
        includeFontPadding: false,
    },
    textGrayMedium: {
        fontSize: 16,
        lineHeight: 24,
        letterSpacing:-1.6,
        color: '#b9bac4',
        fontFamily: Theme.Fonts.Medium,
        includeFontPadding: false,
    },
    textMediumLarge: {
        fontSize: 18,
        lineHeight: 27,
        letterSpacing:-1.8,
        color: 'black',
        fontFamily: Theme.Fonts.Medium,
        includeFontPadding: false,
    },
    text: {
        fontSize: 16,
        lineHeight: 24,
        letterSpacing:-1.6,
        color: 'black',
        fontFamily: Theme.Fonts.Regular,
        includeFontPadding: false,
    },
    textLight: {
        fontSize: 16,
        lineHeight: 24,
        letterSpacing:-1.6,
        color: 'black',
        fontFamily: Theme.Fonts.Light,
        includeFontPadding: false,
    },
    textGray: {
        fontSize: 14,
        lineHeight: 20,
        letterSpacing:-1.4,
        color: '#b9bac4',
        fontFamily: Theme.Fonts.Regular,
        includeFontPadding: false,
    },
    textLightGray: {
        fontSize: 14,
        lineHeight: 20,
        letterSpacing:-0.7,
        color: '#707070',
        fontFamily: Theme.Fonts.Light,
        includeFontPadding: false,
    },
    textLightGrayLarge: {
        fontSize: 16,
        lineHeight: 24,
        letterSpacing:-1.6,
        color: '#9aa3ac',
        fontFamily: Theme.Fonts.Light,
        includeFontPadding: false,
    },
    textLightGrayLargeTypeRounded: {
        fontSize: 16,
        lineHeight: 24,
        letterSpacing:-1.6,
        color: '#9aa3ac',
        fontFamily: Theme.Fonts.Regular,
        includeFontPadding: false,
        width:38,
        paddingLeft:2,
        lineHeight:20,
        paddingLeft:6
    },
    textRobotoLight: {
        fontSize: 16,
        lineHeight: 21,
        color: 'black',
        fontFamily: Theme.Fonts.RobotoLight,
        includeFontPadding: false,
    },
    vertical: {
        flexDirection: 'column',
        alignItems: 'flex-start',
    },
    horizon: {
        flexDirection: 'row',
        alignItems: 'center',
    },
    center: {
        alignItems: 'center',
        justifyContent: 'center',
    }
});