import React from 'react';
import { Text, View } from 'react-native';
import { Audio } from 'expo-av';
import { BorderlessButton } from 'react-native-gesture-handler';
import { getInfoAsync } from 'expo-file-system';
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';

import styles from './styles';
import I18n from '../../i18n';
import { themes } from '../../constants/colors';
import { CustomIcon } from '../../lib/Icons';
import { events, logEvent } from '../../utils/log';

interface IMessageBoxRecordAudioProps {
	theme: string;
	recordingCallback: Function;
	onFinish: Function;
}

const RECORDING_EXTENSION = '.aac';
const RECORDING_SETTINGS = {
	android: {
		extension: RECORDING_EXTENSION,
		outputFormat: Audio.RECORDING_OPTION_ANDROID_OUTPUT_FORMAT_AAC_ADTS,
		audioEncoder: Audio.RECORDING_OPTION_ANDROID_AUDIO_ENCODER_AAC,
		sampleRate: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.android.sampleRate,
		numberOfChannels: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.android.numberOfChannels,
		bitRate: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.android.bitRate
	},
	ios: {
		extension: RECORDING_EXTENSION,
		audioQuality: Audio.RECORDING_OPTION_IOS_AUDIO_QUALITY_MIN,
		sampleRate: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.ios.sampleRate,
		numberOfChannels: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.ios.numberOfChannels,
		bitRate: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.ios.bitRate,
		outputFormat: Audio.RECORDING_OPTION_IOS_OUTPUT_FORMAT_MPEG4AAC
	}
};
const RECORDING_MODE = {
	allowsRecordingIOS: true,
	playsInSilentModeIOS: true,
	staysActiveInBackground: false,
	shouldDuckAndroid: true,
	playThroughEarpieceAndroid: false,
	interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
	interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX
};

const formatTime = function (seconds: any) {
	let minutes: any = Math.floor(seconds / 60);
	seconds %= 60;
	if (minutes < 10) {
		minutes = `0${minutes}`;
	}
	if (seconds < 10) {
		seconds = `0${seconds}`;
	}
	return `${minutes}:${seconds}`;
};

export default class RecordAudio extends React.PureComponent<IMessageBoxRecordAudioProps, any> {
	private isRecorderBusy: boolean;

	private recording: any;

	constructor(props: IMessageBoxRecordAudioProps) {
		super(props);
		this.isRecorderBusy = false;
		this.state = {
			isRecording: false,
			recordingDurationMillis: 0
		};
	}

	componentDidUpdate() {
		const { recordingCallback } = this.props;
		const { isRecording } = this.state;

		recordingCallback(isRecording);
	}

	componentWillUnmount() {
		if (this.recording) {
			this.cancelRecordingAudio();
		}
	}

	get duration() {
		const { recordingDurationMillis } = this.state;
		return formatTime(Math.floor(recordingDurationMillis / 1000));
	}

	isRecordingPermissionGranted = async () => {
		try {
			const permission = await Audio.getPermissionsAsync();
			if (permission.status === 'granted') {
				return true;
			}
			await Audio.requestPermissionsAsync();
		} catch {
			// Do nothing
		}
		return false;
	};

	onRecordingStatusUpdate = (status: any) => {
		this.setState({
			isRecording: status.isRecording,
			recordingDurationMillis: status.durationMillis
		});
	};

	startRecordingAudio = async () => {
		logEvent(events.ROOM_AUDIO_RECORD);
		if (!this.isRecorderBusy) {
			this.isRecorderBusy = true;
			try {
				const canRecord = await this.isRecordingPermissionGranted();
				if (canRecord) {
					await Audio.setAudioModeAsync(RECORDING_MODE);

					this.recording = new Audio.Recording();
					await this.recording.prepareToRecordAsync(RECORDING_SETTINGS);
					this.recording.setOnRecordingStatusUpdate(this.onRecordingStatusUpdate);

					await this.recording.startAsync();
					activateKeepAwake();
				} else {
					await Audio.requestPermissionsAsync();
				}
			} catch (error) {
				logEvent(events.ROOM_AUDIO_RECORD_F);
			}
			this.isRecorderBusy = false;
		}
	};

	finishRecordingAudio = async () => {
		logEvent(events.ROOM_AUDIO_FINISH);
		if (!this.isRecorderBusy) {
			const { onFinish } = this.props;

			this.isRecorderBusy = true;
			try {
				await this.recording.stopAndUnloadAsync();

				const fileURI = this.recording.getURI();
				const fileData = await getInfoAsync(fileURI);
				const fileInfo = {
					name: `${Date.now()}.aac`,
					mime: 'audio/aac',
					type: 'audio/aac',
					store: 'Uploads',
					path: fileURI,
					size: fileData.size
				};

				onFinish(fileInfo);
			} catch (error) {
				logEvent(events.ROOM_AUDIO_FINISH_F);
			}
			this.setState({ isRecording: false, recordingDurationMillis: 0 });
			deactivateKeepAwake();
			this.isRecorderBusy = false;
		}
	};

	cancelRecordingAudio = async () => {
		logEvent(events.ROOM_AUDIO_CANCEL);
		if (!this.isRecorderBusy) {
			this.isRecorderBusy = true;
			try {
				await this.recording.stopAndUnloadAsync();
			} catch (error) {
				logEvent(events.ROOM_AUDIO_CANCEL_F);
			}
			this.setState({ isRecording: false, recordingDurationMillis: 0 });
			deactivateKeepAwake();
			this.isRecorderBusy = false;
		}
	};

	render() {
		const { theme } = this.props;
		const { isRecording } = this.state;

		if (!isRecording) {
			return (
				<BorderlessButton
					onPress={this.startRecordingAudio}
					style={styles.actionButton}
					testID='messagebox-send-audio'
					// @ts-ignore
					accessibilityLabel={I18n.t('Send_audio_message')}
					accessibilityTraits='button'>
					<CustomIcon name='microphone' size={24} color={themes[theme].auxiliaryTintColor} />
				</BorderlessButton>
			);
		}

		return (
			<View style={styles.recordingContent}>
				<View style={styles.textArea}>
					<BorderlessButton
						onPress={this.cancelRecordingAudio}
						// @ts-ignore
						accessibilityLabel={I18n.t('Cancel_recording')}
						accessibilityTraits='button'
						style={styles.actionButton}>
						<CustomIcon size={24} color={themes[theme].dangerColor} name='close' />
					</BorderlessButton>
					<Text style={[styles.recordingCancelText, { color: themes[theme].titleText }]}>{this.duration}</Text>
				</View>
				<BorderlessButton
					onPress={this.finishRecordingAudio}
					// @ts-ignore
					accessibilityLabel={I18n.t('Finish_recording')}
					accessibilityTraits='button'
					style={styles.actionButton}>
					<CustomIcon size={24} color={themes[theme].successColor} name='check' />
				</BorderlessButton>
			</View>
		);
	}
}