/* eslint-disable no-case-declarations */

import { find } from 'lodash';
import {
	SITE_DOMAINS_RECEIVE,
	SITE_DOMAINS_REQUEST,
	SITE_DOMAINS_REQUEST_SUCCESS,
	SITE_DOMAINS_REQUEST_FAILURE,
	DOMAIN_DNSSEC_DISABLE_SUCCESS,
	DOMAIN_DNSSEC_ENABLE_SUCCESS,
	DOMAIN_PRIVACY_ENABLE,
	DOMAIN_PRIVACY_DISABLE,
	DOMAIN_PRIVACY_ENABLE_SUCCESS,
	DOMAIN_PRIVACY_DISABLE_SUCCESS,
	DOMAIN_PRIVACY_ENABLE_FAILURE,
	DOMAIN_PRIVACY_DISABLE_FAILURE,
	DOMAIN_CONTACT_INFO_DISCLOSE,
	DOMAIN_CONTACT_INFO_DISCLOSE_SUCCESS,
	DOMAIN_CONTACT_INFO_DISCLOSE_FAILURE,
	DOMAIN_CONTACT_INFO_REDACT,
	DOMAIN_CONTACT_INFO_REDACT_SUCCESS,
	DOMAIN_CONTACT_INFO_REDACT_FAILURE,
	DOMAIN_MARK_AS_PENDING_MOVE,
	DOMAIN_MANAGEMENT_PRIMARY_DOMAIN_SAVE_SUCCESS,
	DOMAIN_MANAGEMENT_PRIMARY_DOMAIN_UPDATE,
	DOMAIN_DETAILS_RECEIVE,
	DOMAIN_DETAILS_REQUEST,
	DOMAIN_DETAILS_REQUEST_FAILURE,
	DOMAIN_DETAILS_REQUEST_SUCCESS,
} from 'calypso/state/action-types';
import { combineReducers, withSchemaValidation } from 'calypso/state/utils';
import { itemsSchema } from './schema';

/**
 * Returns a copy of the domains state object with some modifications
 * @param {Object} state - current state
 * @param {number} siteId - site ID
 * @param {string} domain - domain name
 * @param {Object} modifyDomainProperties - object with modified site domain properties
 * @returns {any} - new copy of the state
 */
const modifySiteDomainObjectImmutable = ( state, siteId, domain, modifyDomainProperties ) => {
	// state[ siteId ] might not be defined yet when using the `domain-details` query
	if ( ! state[ siteId ] ) {
		return Object.assign( {}, state, {
			[ siteId ]: [ { ...modifyDomainProperties } ],
		} );
	}

	// Find the domain we want to update
	const targetDomain = find( state[ siteId ], { domain: domain } );
	const domainIndex = state[ siteId ].indexOf( targetDomain );
	// Copy as we shouldn't mutate original state
	const newDomains = [ ...state[ siteId ] ];
	// Update privacy
	if ( domainIndex === -1 ) {
		newDomains.push( Object.assign( {}, targetDomain, modifyDomainProperties ) );
	} else {
		newDomains.splice( domainIndex, 1, Object.assign( {}, targetDomain, modifyDomainProperties ) );
	}

	return Object.assign( {}, state, {
		[ siteId ]: newDomains,
	} );
};

/**
 * Domains `Reducer` function
 * @param {Object} state - current state
 * @param {Object} action - domains action
 * @returns {Object} updated state
 */
export const items = withSchemaValidation( itemsSchema, ( state = {}, action ) => {
	const { siteId } = action;
	switch ( action.type ) {
		case SITE_DOMAINS_RECEIVE:
			return Object.assign( {}, state, {
				[ siteId ]: action.domains,
			} );
		case DOMAIN_PRIVACY_ENABLE_SUCCESS:
			return modifySiteDomainObjectImmutable( state, siteId, action.domain, {
				privateDomain: true,
				contactInfoDisclosed: false,
			} );
		case DOMAIN_PRIVACY_DISABLE_SUCCESS:
			return modifySiteDomainObjectImmutable( state, siteId, action.domain, {
				privateDomain: false,
				contactInfoDisclosed: false,
			} );
		case DOMAIN_CONTACT_INFO_DISCLOSE_SUCCESS:
			return modifySiteDomainObjectImmutable( state, siteId, action.domain, {
				privateDomain: false,
				contactInfoDisclosed: true,
			} );
		case DOMAIN_CONTACT_INFO_REDACT_SUCCESS:
			return modifySiteDomainObjectImmutable( state, siteId, action.domain, {
				privateDomain: false,
				contactInfoDisclosed: false,
			} );
		case DOMAIN_MARK_AS_PENDING_MOVE:
			return modifySiteDomainObjectImmutable( state, siteId, action.domain, {
				isMoveToNewSitePending: true,
			} );
		case DOMAIN_DNSSEC_DISABLE_SUCCESS:
			return modifySiteDomainObjectImmutable( state, siteId, action.domain, {
				isDnssecEnabled: false,
				dnssecRecords: null,
			} );
		case DOMAIN_DNSSEC_ENABLE_SUCCESS:
			return modifySiteDomainObjectImmutable( state, siteId, action.domain, {
				isDnssecEnabled: true,
				dnssecRecords: action.dnssecRecords,
			} );
		case DOMAIN_DETAILS_RECEIVE:
			return modifySiteDomainObjectImmutable( state, siteId, action.domain, {
				...action.domainDetails,
			} );
	}

	return state;
} );

/**
 * Updating privacy reducer
 *
 * Figure out if we're in the middle of privacy modification command
 * @param {Object} state - current state
 * @param {Object} action - action
 * @returns {any} - new state
 */
export const updatingPrivacy = ( state = {}, action ) => {
	switch ( action.type ) {
		case DOMAIN_PRIVACY_ENABLE:
		case DOMAIN_PRIVACY_ENABLE_SUCCESS:
		case DOMAIN_PRIVACY_ENABLE_FAILURE:
		case DOMAIN_PRIVACY_DISABLE:
		case DOMAIN_PRIVACY_DISABLE_SUCCESS:
		case DOMAIN_PRIVACY_DISABLE_FAILURE:
		case DOMAIN_CONTACT_INFO_DISCLOSE:
		case DOMAIN_CONTACT_INFO_DISCLOSE_SUCCESS:
		case DOMAIN_CONTACT_INFO_DISCLOSE_FAILURE:
		case DOMAIN_CONTACT_INFO_REDACT:
		case DOMAIN_CONTACT_INFO_REDACT_SUCCESS:
		case DOMAIN_CONTACT_INFO_REDACT_FAILURE:
			return Object.assign( {}, state, {
				[ action.siteId ]: {
					[ action.domain ]:
						[
							DOMAIN_PRIVACY_ENABLE,
							DOMAIN_PRIVACY_DISABLE,
							DOMAIN_CONTACT_INFO_DISCLOSE,
							DOMAIN_CONTACT_INFO_REDACT,
						].indexOf( action.type ) !== -1,
				},
			} );
	}

	return state;
};

/**
 * Updating privacy reducer
 *
 * Figure out if we're in the middle of privacy modification command
 * @param {Object} state - current state
 * @param {Object} action - action
 * @returns {any} - new state
 */
export const updatingPrimaryDomain = ( state = {}, action ) => {
	switch ( action.type ) {
		case DOMAIN_MANAGEMENT_PRIMARY_DOMAIN_UPDATE:
			return Object.assign( {}, state, {
				[ action.siteId ]: true,
			} );
		case DOMAIN_MANAGEMENT_PRIMARY_DOMAIN_SAVE_SUCCESS:
			return Object.assign( {}, state, {
				[ action.siteId ]: false,
			} );
	}
	return state;
};

/**
 * `Reducer` function which handles request/response actions
 * to/from WP REST-API
 * @param {Object} state - current state
 * @param {Object} action - domains action
 * @returns {Object} updated state
 */
export const requesting = ( state = {}, action ) => {
	switch ( action.type ) {
		case SITE_DOMAINS_REQUEST:
		case SITE_DOMAINS_REQUEST_SUCCESS:
		case SITE_DOMAINS_REQUEST_FAILURE:
			return Object.assign( {}, state, {
				[ action.siteId ]: action.type === SITE_DOMAINS_REQUEST,
			} );
		case DOMAIN_DETAILS_REQUEST:
		case DOMAIN_DETAILS_REQUEST_SUCCESS:
		case DOMAIN_DETAILS_REQUEST_FAILURE:
			return Object.assign( {}, state, {
				[ action.domain ]: action.type === DOMAIN_DETAILS_REQUEST,
			} );
	}

	return state;
};

/**
 * `Reducer` function which handles ERRORs REST-API response actions
 * @param {Object} state - current state
 * @param {Object} action - domains action
 * @returns {Object} updated state
 */
export const errors = ( state = {}, action ) => {
	switch ( action.type ) {
		case SITE_DOMAINS_REQUEST:
		case SITE_DOMAINS_REQUEST_SUCCESS:
			return Object.assign( {}, state, {
				[ action.siteId ]: null,
			} );

		case SITE_DOMAINS_REQUEST_FAILURE:
			return Object.assign( {}, state, {
				[ action.siteId ]: action.error,
			} );
		case DOMAIN_DETAILS_REQUEST:
		case DOMAIN_DETAILS_REQUEST_SUCCESS:
			return Object.assign( {}, state, {
				[ action.domain ]: null,
			} );
		case DOMAIN_DETAILS_REQUEST_FAILURE:
			return Object.assign( {}, state, {
				[ action.domain ]: action.error,
			} );
	}

	return state;
};

export default combineReducers( {
	errors,
	items,
	requesting,
	updatingPrivacy,
	updatingPrimaryDomain,
} );
