import React, { useState, Fragment, useCallback, useEffect, useRef, useLayoutEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import Styled from 'styled-components/native';
import Theme from '~/Themes';
import { showSelectorAction } from '~/GlobalReducers/uploadfile';
import { showCameraAction } from '~/GlobalReducers/camera';
import * as Permissions from 'expo-permissions';
import * as DocumentPicker from 'expo-document-picker';
import * as FileSystem from 'expo-file-system';
import { WebView } from 'react-native-webview';
import { Alert, ActivityIndicator, Image, View, TouchableOpacity, Modal, Platform, Linking, BackHandler, Keyboard } from 'react-native';
import { useToast } from './Message';
import { fetchPost } from '~/Utils/fetch';
import FileSvg from '~/Assets/Svgs/file_text.svg';
import Icon from './Icon';
import ImageZoomViewer from 'react-native-image-zoom-viewer';
import * as MediaLibrary from 'expo-media-library';
import { Util } from '~/Utils/utils';
import { ImageViewer } from './ImageViewer';
import { Camera } from 'expo-camera';
import { Config } from '~/Configuration';
import { useDownload } from './Download';
import { isTrue } from './Common';

const Wrapper = Styled.View`
    flex-direction: column;
    flex: 1;
`;
const Container = Styled.View`
    flex-direction: row;
    height: 40px;
    border: 1px solid #b9bac4;
    border-radius: 5px;
    align-items: center;
    padding-left: 19px;
    padding-right: 0px;
    background-color: white;
    overflow: hidden;
`;
const Label = Styled.Text`
    font-size: 16px;
    font-family: ${Theme.Fonts.Regular};
    include-font-padding: false;
    align-items: center;
    color: #43425d;
    flex: 1;
    text-align-vertical: center;
`;
const DefaultLabel = Styled(Label)`
    color: #9aa3ac;
`;
const Button = Styled.TouchableOpacity`
    flex-direction: row;
    width: 81px;
    height: 100%;
    background-color: #9aa3ac;
    border: 0px;
    border-left-width: 1px;
    border-color: #b9bac4;
    justify-content: center;
    align-items: center;
`;
const ButtonLabel = Styled.Text`
    font-size: 14;
    font-family: ${Theme.Fonts.Regular};
    include-font-padding: false;
    line-height: 16;
    letter-spacing:-1.2;
    color: #ffffff;
`;
const ImageContainer = Styled.TouchableOpacity`
    flex-direction: row;
    height: 200px;
    min-height: 200px;
    border: 1px solid #d8d8d8;
    align-items: center;
    justify-content: center;
    padding-left: 0px;
    padding-right: 0px;
    background-color: #f5f5f5;
    border-radius: 5px;
    overflow: hidden;
`;
const ImageDeleteContainer = Styled.TouchableOpacity`
    position: absolute;
    width: 23px;
    height: 23px;
    right: 15px;
    bottom: 10px;
    border-radius: 11.5;
    background-color: white;
    align-items: center;
    justify-content: center;
`;
const FileContainer = Styled.View`
    flex-direction: row;
    height: 40px;
    min-height: 40px;
    border: 1px solid #d8d8d8;
    align-items: center;
    justify-content: center;
    padding-left: 0px;
    padding-right: 0px;
    background-color: #f5f5f5;
    border-radius: 5px;
    overflow: hidden;
`;
const FileLabel = Styled.Text`
    font-size: 16px;
    font-family: ${Theme.Fonts.Regular};
    include-font-padding: false;
    align-items: center;
    color: #43425d;
    flex: 1;
    text-align-vertical: center;
    padding-left: 10px;
    padding-right: 10px;
`;
const FileDeleteContainer = Styled.TouchableOpacity`
    width: 23px;
    height: 23px;
    border-radius: 11.5;
    background-color: white;
    align-items: center;
    justify-content: center;
`;

const UploadActionContainer = Styled.View`
    position: absolute;
    right: 0;
    width: 160px;
    height: 40px;
    background-color: red;
    border-radius: 5px;
    overflow: hidden;
`;

const getFileMimeType = (name) => {
    const nameAndExt = name.split('.');
    let ext = '';
    let mimeType = 'application/octet-stream';
    if(nameAndExt.length >= 2) {
        ext = (nameAndExt[nameAndExt.length-1] + '').toLowerCase();
    }
    if(ext == 'jpg') ext = 'jpeg';
    if(ext == 'gif' || ext == 'jpeg' || ext == 'bmp' || ext == 'png') mimeType = 'image/' + ext;
    if(ext == 'pdf') mimeType = 'application/pdf';
    return mimeType;
}

const isImage = (mimeType) => {
    if(mimeType.indexOf('image/') === 0) {
        return true;
    }
    return false;
}

const onUploadDefault = (isUpload, result={}) => {};
export const UploadFileType = {
    Image: 'IMAGE',
    File: 'FILE',
}
const initialFile = {Name:'',Path:'',Url:''};
export default UploadFile = ({
    style={}, textContainerStyle={}, textStyle={}, imageContainerStyle={}, fileContainerStyle={}, 
    defaultFile=initialFile, type=UploadFileType.Image, mimeType="*/*", placeholder='선택', onUpload=onUploadDefault, onDelete=()=>{}, editable=true
}) => {
    const [loading, setLoading] = useState(false);
    const [imageLoading, setImageLoading] = useState(false);
    const [file, setFile] = useState(defaultFile); // {Name, Path, Url}
    const [cancelUpload, setCancelUpload] = useState(null);
    const [downloadState, setDownloadState] = useState({ downloading: false, source: { html : '<h1>Download</h1>' }});
    const [showDetail, setShowDetail] = useState(false);
    const fileIsImage = useRef(isImage(getFileMimeType(Util.nvl(Util.get(defaultFile, "Name"), ''))));
    const { showMessage } = useToast();

    // redux
    const dispatch = useDispatch();

    // camera redux
    const cameraPayload = useSelector(({GlobalCamera}) => GlobalCamera.camera);
    const showCamera = useCallback((payload) => dispatch(showCameraAction(payload)), []);
    const showCameraParameter = {
        show: true,
        onTakePicture: async (picture) => {
            console.log('on take picture - ', picture);
            const filename = `${Util.formatDate(new Date(), 'yyyyMMddhhmmsszzz')}.jpg`;
            let uploadResult = null;
            setLoading(true);
            try {
                fileIsImage.current = true;
                uploadResult = await upload(picture.uri, filename);
            } catch(error) {
                uploadResult = null;
                if(defaultFile == null) {
                    setFile(initialFile);
                } else {
                    setFile(defaultFile);
                }
                showMessage(error.message);
            } finally {
                setLoading(false);
            }

            if(uploadResult != null) {
                setFile(uploadResult);
                onUpload(true, uploadResult);
            }
        },
        onCancel: () => {
        }
    }

    // selector redux
    const payload = useSelector(({GlobalUploadFile}) => GlobalUploadFile.selector);
    const showSelector = useCallback((payload) => dispatch(showSelectorAction(payload)), []);
    const showSelectorParameter = {
        showSelector: true,
        type: type,
        onSelect: (action) => {
            console.log('upload file select : ', action);
            if(action == 'camera') {
                showCamera(showCameraParameter);
            } else if(action == 'file') {
                pickFile();
            }
        }
    }

    const selectFile = () => {
        if(type == UploadFileType.Image) {
            showSelector(showSelectorParameter);
        } else {
            pickFile();
        }
    }


    useEffect(() => {
        console.log('================================ upload file changed value... ');
        console.log('defaultFile : ', defaultFile);
        fileIsImage.current = isImage(getFileMimeType(Util.nvl(Util.get(defaultFile, "Name"), '')));
        setFile(defaultFile);
    }, [defaultFile, editable]);

    const checkGrant = async () => {
        if((await Permissions.getAsync(Permissions.CAMERA_ROLL)).status != 'granted') {
            if((await Permissions.askAsync(Permissions.CAMERA_ROLL)).status != 'granted') {
                Alert.alert('이미지/파일을 선택하려면 권한을 허용해야 선택 가능합니다.');
                return false;
            }
        }
        return true;
    }

    const pickFile = async () => {
        let uploadResult = null;
        try {
            if(!await checkGrant()) return;

            setLoading(true);
            const result = await DocumentPicker.getDocumentAsync({
                type: mimeType,//(type == UploadFileType.File ? '*/*' : 'image/*'),
            });
            console.log('pick result - ', result);
            if(result.type == "success") {
                fileIsImage.current = isImage(getFileMimeType(result.name));
                uploadResult = await upload(result.uri, result.name);
            }
            setLoading(false);
        } catch(error) {
            console.log('pickFile error - ', error);
            uploadResult = null;
            if(defaultFile == null) {
                setFile(initialFile);
            } else {
                setFile(defaultFile);
            }
            setLoading(false);
            showMessage(error.message);
        }

        if(uploadResult != null) {
            setFile(uploadResult);
            onUpload(true, uploadResult);
        }
    }

    const upload = async (uri, name) => {
        let formData = new FormData();
        formData.append('file', {
            uri,
            name: name,
            type: getFileMimeType(name),
        });

        let result = null;
        try {
            setCancelUpload(null);
            const fetchUrl = (type == UploadFileType.Image ? 'api/control/uploadimage' : 'api/control/upload');
            result = await fetchPost(fetchUrl, formData, {'Content-Type': 'multipart/form-data'}, true, 15000, (cancel)=>{
                console.log('provide cancel');
                setCancelUpload({ cancel: cancel });
            });
            setCancelUpload(null);
        } catch(error) {
            console.log('upload error - ', error);
            throw error;
        }

        return result;
    }

    const download = async(url, name = '') => {
        const dotPos = (name+'').lastIndexOf('.');
        let filename = '';
        let extension = '';
        if(dotPos == -1) {
            filename = name;
        } else {
            filename = name.substr(0, dotPos);
            extension = name.substr(dotPos);
        }

        let file = filename;
        let index = 0;
        try {
            while(true) {
                const info = await FileSystem.getInfoAsync(FileSystem.documentDirectory + file + extension);
                if(!info.exists) break;

                index ++;
                file = filename + '(' + index + ')';
            }

            const result = await FileSystem.downloadAsync(url, FileSystem.documentDirectory + file + extension);
            console.log('download complete : ', result);
            await saveFile(result.uri);
            showMessage('다운로드 되었습니다.');
        } catch(error) {
            console.error(url, 'download error : ', error);
            showMessage(error.message);
        }
    }

    const { downloadFromPath } = useDownload();

    const saveFile = async (uri) => {
        const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
        if(status === 'granted') {
            const asset = await MediaLibrary.createAssetAsync(uri);
            await MediaLibrary.createAlbumAsync('Download', asset, false);
        }
    }

    const LoadingStyle = loading ? {paddingLeft:0, justifyContent:'center', alignItems:'center'} : {};
    const borderStyle = isTrue(editable) ? { borderColor: Theme.COLORS.EDITABLE_BORDER } : { borderColor: Theme.COLORS.READONLY_BORDER };
    const backgroundStyle = isTrue(editable) ? { backgroundColor: Theme.COLORS.EDITABLE_BACKGROUND } : { backgroundColor: Theme.COLORS.READONLY_BACKGROUND };

    return (
        <Wrapper style={[style]}>
            <Container style={[textContainerStyle, backgroundStyle, borderStyle, LoadingStyle]}>
                {loading ? (
                    <Fragment>
                        <View style={{flex:1}}>
                            <ActivityIndicator size="small" color="#43425d" />
                        </View>
                        <Button onPress={() => { if(cancelUpload != null) cancelUpload.cancel('업로드가 취소되었습니다.') }}><ButtonLabel>취소</ButtonLabel></Button>
                    </Fragment>
                ) : (
                    <Fragment>
                        {isTrue(editable) ? (
                            <Fragment>
                            {file == null || file.Name == '' ? (
                                <DefaultLabel style={[textStyle]} numberOfLines={1} ellipsizeMode="middle">{placeholder}</DefaultLabel>
                            ) : (
                                <Label style={[textStyle]} numberOfLines={1} ellipsizeMode="middle">{file.Name}</Label>
                            )}
                            </Fragment>
                        ) : (
                            <Label style={[textStyle]} numberOfLines={1} ellipsizeMode="middle">{file == null ? "" : file.Name}</Label>
                        )}
                        {isTrue(editable) && <Button onPress={() => { selectFile() }}><ButtonLabel>파일선택</ButtonLabel></Button>}
                    </Fragment>
                )}
            </Container>
            {!fileIsImage.current && file != null && file.Url != '' ? (
                <FileContainer style={[{marginTop:5}, fileContainerStyle]}>
                    <TouchableOpacity style={{flexDirection:'row', flex:1, alignItems:'center'}} onPress={() => {
                        console.log(file);
                        if(file.Path && file.Name) {
                            //console.log(`${Config.BASE_URL}/api/FileDownload/DownloadFile?filePath=${encodeURIComponent(file.Path)}&fileName=${encodeURIComponent(file.Name)}`);
                            Linking.openURL(`${Config.BASE_URL}/api/FileDownload/DownloadFile?filePath=${encodeURIComponent(file.Path)}&fileName=${encodeURIComponent(file.Name)}`);
                            //downloadFromPath({ path:file.Path, name:file.Name });
                        } else {
                            Linking.openURL(file.Url);
                        }
                    }}>
                        <FileSvg width={20} height={16} color="#9aa3ac" />
                        <FileLabel numberOfLines={1} ellipsizeMode="middle">{file.Name}</FileLabel>
                    </TouchableOpacity>
                    {isTrue(editable) && (
                        <FileDeleteContainer onPress={() => {
                            setFile({Name:'',Path:'',Url:''});
                            onDelete();
                        }}>
                            <Icon iconFamily="AntDesign" iconName="close" color="#69717a" size={16} />
                        </FileDeleteContainer>
                    )}
                </FileContainer>
            ) : null}
            {fileIsImage.current && file != null && file.Url != '' ? (
                <Fragment>
                    <Modal visible={showDetail} transparent={false} onRequestClose={() => setShowDetail(false)}>
                        {/*
                        <ImageZoomViewer imageUrls={[{url:file.Url}]} />
                        */}
                        <ImageViewer source={{uri:file.Url}} />
                        
                        <TouchableOpacity style={{
                            position:'absolute', right:10, top:30, width:50, height:50, 
                            borderRadius:25, backgroundColor:'white', overflow:'hidden',
                            justifyContent:'center', alignItems:'center'
                        }} onPress={() => setShowDetail(false)}>
                            <Icon iconFamily="AntDesign" iconName="close" color="#69717a" size={50} />
                        </TouchableOpacity>
                    </Modal>
                    <ImageContainer style={[{marginTop:5}, imageContainerStyle]} onPress={() => setShowDetail(true)}>
                        <Image style={{width: '100%', height: '100%'}} resizeMode='contain' source={{uri:file.Url,cache:'reload',headers:{Pragma:'no-cache'}}} onLoadStart={() => {
                            console.log('onLoadStart...............');
                            setImageLoading(true);
                        }} onLoadEnd={() => {
                            console.log('onLoadEnd...............');
                            setImageLoading(false);
                        }} onError={() => {
                            console.log('onLoadError...............');
                            setImageLoading(false);
                        }}/>
                        {imageLoading && (
                            <ActivityIndicator size="large" color="white" style={{ position: 'absolute', alignSelf: 'center', alignContent: 'center' }} />
                        )}
                        {isTrue(editable) && (
                            <ImageDeleteContainer onPress={() => {
                                setFile({Name:'',Path:'',Url:''});
                                onDelete();
                            }}>
                                <Icon iconFamily="AntDesign" iconName="close" color="#69717a" size={16} />
                            </ImageDeleteContainer>
                        )}
                    </ImageContainer>
                </Fragment>
            ) : null}
            {/*
            <WebView originWhitelist={['*']} 
                source={downloadState.source} 
                style={{display:'none', height:100}} 
                onLoadStart={(event) => {

                }}
                onLoadEnd={(event) => {
                    setDownloadState({ ...downloadState, downloading: false });
                }}
                onError={(event) => {

                }}
                onHttpError={(event) => {

                }} />
            */}
        </Wrapper>
    )
}



const ProviderBackground = Styled.TouchableOpacity`
    position: absolute;
    left:0; top:0; right:0; bottom:0;
    background-color: black;
    opacity: 0.6;
`;
const ProviderContainer = Styled.View`
    position: absolute;
    left:0; top:0; right:0; bottom:0;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
`;
const ProviderContent = Styled.View`
    position: absolute;
    left: 0px;
    right: 0px;
    bottom: 50px;
    height: 200px;
    flex-direction: row;
    align-items: center;
    justify-content: center;
`;
const Item = Styled.TouchableOpacity`
    width: 150px;
    height: 150px;
    background-color: white;
    border-radius: 5px;
    overflow: hidden;
    margin: 10px;
    align-items: center;
    justify-content: center;
`;
const ItemText = Styled.Text`
    font-family: ${Theme.Fonts.Regular};
    font-size: 18;
    line-height: 22;
    include-font-padding: false;
    margin-top: 20px;
`;

export const UploadFileProvider = () => {
    const payload = useSelector(({GlobalUploadFile}) => GlobalUploadFile.selector);
    const dispatch = useDispatch();
    const showSelector = useCallback((payload) => dispatch(showSelectorAction(payload)), []);
    const backHandler = useRef(null);

    if(payload.showSelector) {
        Keyboard.dismiss();
    }

    useLayoutEffect(() => {
        if(backHandler.current != null) backHandler.current.remove();

        backHandler.current = BackHandler.addEventListener('hardwareBackPress', () => {
            showSelector({
                showSelector: false,
                onSelect: payload.onSelect
            });

            if(payload.showSelector) {
                return true;
            } else {
                return false;
            }
        });
    }, [payload]);

    return (
        payload.showSelector && (
        <>
            <ProviderBackground onPress={() => {
                showSelector({
                    showSelector: false,
                    onSelect: payload.onSelect
                });
            }} />
            <ProviderContent>
                {payload.type == UploadFileType.Image && (
                <Item onPress={() => { payload.onSelect('camera'); showSelector({ showSelector: false, onSelect: payload.onSelect }); }}>
                    <Icon iconFamily="AntDesign" iconName="camera" size={50} color="black" />
                    <ItemText>사진촬영</ItemText>
                </Item>
                )}
                <Item onPress={() => { payload.onSelect('file'); showSelector({ showSelector: false, onSelect: payload.onSelect }); }}>
                    <Icon iconFamily="AntDesign" iconName="file1" size={50} color="black" />
                    <ItemText>파일선택</ItemText>
                </Item>
            </ProviderContent>
        </>
        )
    )
}


