import { defineStore } from 'pinia';
import api from './api.js';

const FIELD_ERROR_MAP = {
	email_required:      'email',
	email_invalid:       'email',
	email_exists:        'email',
	password_required:   'password',
	password_invalid:    'password',
	credentials_invalid: 'both',
};

const TRACKING_TYPES = [ 'lightweight', 'normal' ];
const DEFAULT_TRACKING_TYPE = 'normal';

function mapCodeToFields( code ) {
	if ( ! code ) return { _global: 'server_error' };
	const target = FIELD_ERROR_MAP[ code ];
	if ( 'email' === target )    return { email: code };
	if ( 'password' === target ) return { password: code };
	if ( 'both' === target )     return { email: code, password: code };
	return { _global: code };
}

export const useAuthStore = defineStore( 'simplestats-auth', {
	state() {
		return {
			draft: {
				email: '',
				password: '',
				tracking_type: DEFAULT_TRACKING_TYPE,
			},
			status: 'idle',           // 'idle' | 'submitting' | 'success' | 'error'
			error: null,              // { code, message }
			fieldErrors: {},          // { email?: code, password?: code, _global?: code }
			flow: null,               // 'sign-up' | 'sign-in' | null
			connectedEmail: null,
		};
	},
	actions: {
		setDraft( patch ) {
			Object.assign( this.draft, patch );
		},

		setTrackingType( value ) {
			this.draft.tracking_type = TRACKING_TYPES.includes( value )
				? value
				: DEFAULT_TRACKING_TYPE;
		},

		clearFieldError( field ) {
			if ( this.fieldErrors[ field ] ) {
				const next = { ...this.fieldErrors };
				delete next[ field ];
				this.fieldErrors = next;
			}
		},

		resetRequest() {
			this.status = 'idle';
			this.error = null;
			this.fieldErrors = {};
		},

		_finishSuccess( email, flow ) {
			this.status = 'success';
			this.error = null;
			this.fieldErrors = {};
			this.connectedEmail = email;
			this.flow = flow;
		},

		_finishFailure( err ) {
			this.status = 'error';
			this.error = err || { code: 'server_error', message: 'Something went wrong.' };
			this.fieldErrors = mapCodeToFields( err && err.code );
		},

		// Stage 1 of sign-up: create the SaaS user account (no website yet). An
		// already-registered email is rejected here — we stay on /sign-up and
		// surface the error rather than advancing to the tracking-type screen.
		// The website itself is created later, in submitConnect().
		//
		// `optin` is the newsletter checkbox: when true the SaaS adds the email
		// to Lindris. Defaults to true to match the checkbox's default state.
		submitSignUp( router, optin = true ) {
			this.resetRequest();
			this.flow = 'sign-up';

			if ( ! this.draft.email ) {
				this.fieldErrors = { email: 'email_required' };
				return;
			}

			this.status = 'submitting';

			return api.createUser( this.draft.email, optin )
				.done( ( data ) => {
					this.connectedEmail = ( data && data.email ) || this.draft.email;
					// Leave status idle so the tracking-type submit is enabled.
					this.status = 'idle';
					router.push( { name: 'tracking-type' } );
				} )
				.fail( ( err ) => {
					// email_exists maps to the email field → SignUpPage renders
					// "An account with that email already exists." and we stay put.
					this._finishFailure( err );
				} );
		},

		// Sign-in is different from sign-up: the SaaS authenticates and tells us
		// whether this WP install already has a site for the account. Only when
		// the site is brand new do we route the user through /tracking-type —
		// otherwise their pick would be silently ignored, which is bad UX.
		submitSignIn( router ) {
			this.resetRequest();
			this.flow = 'sign-in';

			if ( ! this.draft.email ) {
				this.fieldErrors = { email: 'email_required' };
				return;
			}
			if ( ! this.draft.password ) {
				this.fieldErrors = { password: 'password_required' };
				return;
			}

			this.status = 'submitting';

			return api.signIn( this.draft.email, this.draft.password )
				.done( ( data ) => {
					this._finishSuccess( ( data && data.email ) || this.draft.email, 'sign-in' );
					if ( data && data.site_was_new ) {
						// Re-enable the picker's submit by leaving status idle.
						this.status = 'idle';
						router.push( { name: 'tracking-type' } );
					} else {
						router.push( { name: 'connecting' } );
					}
				} )
				.fail( ( err ) => {
					this._finishFailure( err );
					// Stay on /sign-in — error renders inline via reactivity.
				} );
		},

		// Tracking-type confirmed → create the website with the chosen mode and
		// persist the completed connection. Shared by both flows: a fresh sign-up
		// and a sign-in onto a host that had no site yet both finish here.
		submitConnect( router ) {
			this.resetRequest();
			this.status = 'submitting';

			return api.createSite( this.draft.tracking_type )
				.done( () => {
					this._finishSuccess( this.connectedEmail || this.draft.email, this.flow );
					router.push( { name: 'connecting' } );
				} )
				.fail( ( err ) => {
					// No email/password fields exist on the tracking-type screen,
					// so force the error onto the global notice instead of a field
					// that would never render.
					this.status = 'error';
					this.error = err || { code: 'server_error', message: 'Something went wrong.' };
					this.fieldErrors = { _global: ( err && err.code ) || 'server_error' };
					// Stay on /tracking-type — global notice renders inline.
				} );
		},

		submitForgot() {
			this.resetRequest();
			this.flow = null;
			this.status = 'submitting';

			return api.forgotPassword( this.draft.email )
				.done( () => {
					this.status = 'success';
				} )
				.fail( ( err ) => {
					this._finishFailure( err );
				} );
		},
	},
} );
