import { VeSyncAirBypass } from './airBypass';
import { VeSync } from '../vesync';
import { logger } from '../logger';
import { Helpers } from '../helpers';

/**
 * VeSync Air Purifier with Bypass V2
 */
export class VeSyncAirBaseV2 extends VeSyncAirBypass {
    protected _lightDetection: boolean = false;
    protected _lightDetectionState: boolean = false;
    protected setSpeedLevel: number | null = null;
    protected autoPreferences: string[];
    protected enabled: boolean = false;
    protected _mode: string = '';
    protected _speed: number = 0;
    protected _timer: { duration: number; action: string } | null = null;

    constructor(details: Record<string, any>, manager: VeSync) {
        super(details, manager);
        this.autoPreferences = [...this.getConfigAutoPreferences(['default', 'efficient', 'quiet'])];
        logger.debug(`Initialized VeSyncAirBaseV2 device: ${this.deviceName}`);
    }

    protected buildConfigDict(configDict: Record<string, any>): void {
        if (configDict) {
            this.config = {
                ...this.config,  // Preserve existing config
                ...configDict    // Merge in new config
            };
        }
    }

    get mode(): string {
        return this._mode;
    }

    set mode(value: string) {
        this._mode = value;
    }

    get speed(): number {
        return this._speed;
    }

    set speed(value: number) {
        this._speed = value;
    }

    get timer(): { duration: number; action: string } | null {
        return this._timer;
    }

    set timer(value: { duration: number; action: string } | null) {
        this._timer = value;
    }

    /**
     * Check response for bypassV2 purifiers that surface nested result codes.
     */
    protected checkV2Response(response: any, status: number, method: string): boolean {
        // First check basic response structure
        if (!this.checkResponse([response, status], method)) {
            return false;
        }

        // Only apply extended handling to bypassV2 purifiers (Vital/Everest)
        if (!this.requiresPowerSwitchPayload()) {
            return true;
        }

        // These devices frequently succeed with a nested non-zero code
        if (response.result && response.result.code !== undefined && response.result.code !== 0) {
            logger.debug(`${this.deviceName} returned inner code ${response.result.code} for ${method}`);
            logger.debug('BypassV2 purifier reports non-zero inner code but request still succeeded');
            this.connectionStatus = 'online';
            return true;
        }

        return true;
    }

    /**
     * Get device details
     */
    async getDetails(): Promise<Boolean> {
        logger.debug(`Getting details for device: ${this.deviceName}`);
        const [head, body] = this.buildApiDict('getPurifierStatus');

        const [response, status] = await this.callApi(
            '/cloud/v2/deviceManaged/bypassV2',
            'post',
            body,
            head
        );

        const needsV2Handling = this.requiresPowerSwitchPayload();
        
        // First check the outer response
        if (!response || status !== 200) {
            logger.debug(`Error getting purifier details for ${this.deviceName}: Invalid response`);
            this.connectionStatus = 'offline';
            return false;
        }

        // For bypassV2 purifier families the API nests the result and may surface non-zero codes
        if (needsV2Handling && response.result) {
            // Check if we have a valid getPurifierStatus response
            if (response.code === 0 && response.result?.result) {
                const statusResponse = response.result.result;
                
                // If we have valid status data, use it regardless of inner result code
                logger.debug(`Using nested status data for bypassV2 purifier: ${this.deviceName}`);
                this.buildPurifierDict(statusResponse);
                if (statusResponse.configuration) {
                    this.buildConfigDict(statusResponse.configuration);
                }
                // Keep device online since we have valid status
                this.connectionStatus = 'online';
                return true;
            }
        }
        
        // Standard processing for non-bypassV2 devices or when no status data is available
        if (!this.checkResponse([response, status], 'getDetails') || !response?.result) {
            logger.debug('Error getting purifier details');
            this.connectionStatus = 'offline';
            return false;
        }

        const innerResponse = response.result;
        if (innerResponse.code !== 0 || !innerResponse.result) {
            logger.debug('Error in inner response from purifier');
            this.connectionStatus = 'offline';
            return false;
        }

        const deviceData = innerResponse.result;
        this.buildPurifierDict(deviceData);
        if (deviceData.configuration) {
            this.buildConfigDict(deviceData.configuration);
        }
        return true;
    }

    /**
     * Build purifier dictionary
     */
    protected buildPurifierDict(devDict: Record<string, any>): void {
        this.connectionStatus = 'online';
        const powerSwitch = Boolean(devDict.powerSwitch ?? 0);
        this.enabled = powerSwitch;
        this.deviceStatus = powerSwitch ? 'on' : 'off';
        this.mode = devDict.workMode ?? 'manual';

        const reportedFanSpeed = devDict.fanSpeedLevel ?? 0;
        const isAutoSentinel = reportedFanSpeed === 255;
        this.speed = isAutoSentinel ? 0 : reportedFanSpeed;
        this.setSpeedLevel = devDict.manualSpeedLevel ?? 1;

        // Parse filter life with proper fallback handling and logging
        let filterLife = 0;
        if (devDict.filterLifePercent !== undefined) {
            filterLife = devDict.filterLifePercent;
            logger.debug(`${this.deviceName}: Parsed filter life from filterLifePercent: ${filterLife}%`);
        } else if (devDict.filter_life !== undefined) {
            filterLife = devDict.filter_life;
            logger.debug(`${this.deviceName}: Parsed filter life from filter_life fallback: ${filterLife}%`);
        } else {
            logger.debug(`${this.deviceName}: No filter life data found in API response`);
            if (logger.getLevel && logger.getLevel() !== undefined && logger.getLevel()! <= 0) {
                logger.debug(`${this.deviceName}: Device dict structure:`, JSON.stringify(devDict, null, 2));
            }
        }
        
        this.details = {
            ...this.details,
            filter_life: filterLife,
            child_lock: Boolean(devDict.childLockSwitch ?? 0),
            display: Boolean(devDict.screenState ?? 0),
            light_detection_switch: Boolean(devDict.lightDetectionSwitch ?? 0),
            environment_light_state: Boolean(devDict.environmentLightState ?? 0),
            screen_switch: Boolean(devDict.screenSwitch ?? 0),
            screenStatus: Boolean(devDict.screenSwitch ?? 0) ? 'on' : 'off',
            manualSpeedLevel: this.setSpeedLevel,
            mode: this.mode,
            speed: this.speed,
            isAutoSentinel
        };

        if (this.hasFeature('air_quality')) {
            this.details.air_quality_value = devDict.PM25 ?? 0;
            this.details.air_quality = devDict.AQLevel ?? 0;
            const normalizedAirQuality = Helpers.normalizeAirQuality(devDict.AQLevel);
            if (normalizedAirQuality.level >= 1) {
                this.details.air_quality_level = normalizedAirQuality.level;
            }
            this.details.air_quality_label = normalizedAirQuality.label;
        }

        if ('PM1' in devDict) this.details.pm1 = devDict.PM1;
        if ('PM10' in devDict) this.details.pm10 = devDict.PM10;
        if ('AQPercent' in devDict) this.details.aq_percent = devDict.AQPercent;
        if ('fanRotateAngle' in devDict) this.details.fan_rotate_angle = devDict.fanRotateAngle;
        if ('filterOpenState' in devDict) this.details.filter_open_state = Boolean(devDict.filterOpenState);
        
        if ((devDict.timerRemain ?? 0) > 0) {
            this.timer = { duration: devDict.timerRemain, action: 'off' };
        }

        if (typeof devDict.autoPreference === 'object' && devDict.autoPreference) {
            this.details.auto_preference_type = devDict.autoPreference?.autoPreferenceType ?? 'default';
        } else {
            this.details.auto_preference_type = null;
        }
    }

    /**
     * Determine whether this purifier requires the powerSwitch payload and nested response handling.
     */
    private requiresPowerSwitchPayload(): boolean {
        const type = (this.deviceType || '').toUpperCase();
        return type.startsWith('LAP-V') || type.startsWith('LAP-EL');
    }

    /**
     * Override turn on to use the powerSwitch payload required by bypassV2 purifiers.
     */
    override async turnOn(): Promise<boolean> {
        logger.info(`Turning on device: ${this.deviceName}`);
        
        const [head, body] = this.buildApiDict('setSwitch');
        
        // BypassV2 purifiers require powerSwitch toggles; others fall back to the base implementation
        if (this.requiresPowerSwitchPayload()) {
            logger.debug(`Using bypassV2 power payload for ${this.deviceName}`);
            body.payload.data = {
                powerSwitch: 1,
                switchIdx: 0
            };

            const [response, status] = await this.callApi(
                '/cloud/v2/deviceManaged/bypassV2',
                'post',
                body,
                head
            );

            // Use bypassV2 response checking
            const success = this.checkV2Response(response, status, 'turnOn');
            if (success) {
                this.deviceStatus = 'on';
                
                // Force a details update to sync state
                setTimeout(() => {
                    this.getDetails().catch(e => {
                        logger.debug(`Background state refresh failed: ${e}`);
                    });
                }, 1000);
            }
            return success;
        } else {
            // Use parent implementation for non-bypassV2 models
            return super.turnOn();
        }
    }

    /**
     * Override turn off to use the powerSwitch payload required by bypassV2 purifiers.
     */
    override async turnOff(): Promise<boolean> {
        logger.info(`Turning off device: ${this.deviceName}`);
        
        const [head, body] = this.buildApiDict('setSwitch');
        
        // BypassV2 purifiers require powerSwitch toggles; others fall back to the base implementation
        if (this.requiresPowerSwitchPayload()) {
            logger.debug(`Using bypassV2 power payload for ${this.deviceName}`);
            body.payload.data = {
                powerSwitch: 0,
                switchIdx: 0
            };

            const [response, status] = await this.callApi(
                '/cloud/v2/deviceManaged/bypassV2',
                'post',
                body,
                head
            );

            // Use bypassV2 response checking
            const success = this.checkV2Response(response, status, 'turnOff');
            if (success) {
                this.deviceStatus = 'off';
                
                // Force a details update to sync state
                setTimeout(() => {
                    this.getDetails().catch(e => {
                        logger.debug(`Background state refresh failed: ${e}`);
                    });
                }, 1000);
            }
            return success;
        } else {
            // Use parent implementation for non-bypassV2 models
            return super.turnOff();
        }
    }

    /**
     * Override setMode to send workMode payloads for bypassV2 purifiers.
     */
    override async setMode(mode: string): Promise<boolean> {
        const targetMode = mode.toLowerCase();
        const supportedModes = this.modes.map(m => m.toLowerCase());

        if (!supportedModes.includes(targetMode)) {
            const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
            logger.error(`${error} for device: ${this.deviceName}`);
            throw new Error(error);
        }

        // Special handling for Core200S stays the same for all models
        if (this.deviceType.includes('Core200S') && targetMode === 'auto') {
            logger.warn(`Auto mode not supported for ${this.deviceType}, using manual mode instead`);
            return this.setMode('manual');
        }

        // Manual mode should leverage changeFanSpeed to mirror pyvesync behaviour
        if (targetMode === 'manual') {
            const defaultLevel = this.config.levels && this.config.levels.length > 0
                ? this.config.levels[0]
                : 1;
            const desiredLevel = this.details.manualSpeedLevel ?? this.speed ?? defaultLevel;
            const success = await this.changeFanSpeed(desiredLevel);
            if (success) {
                this.details.mode = 'manual';
                this.mode = 'manual';
            }
            return success;
        }

        // BypassV2 purifiers need the workMode payload; other models use the base implementation
        if (this.requiresPowerSwitchPayload()) {
            logger.debug(`Using bypassV2 mode payload for ${this.deviceName}`);
            const [head, body] = this.buildApiDict('setPurifierMode');
            body.payload.data = {
                workMode: targetMode
            };

            const [response, status] = await this.callApi(
                '/cloud/v2/deviceManaged/bypassV2',
                'post',
                body,
                head
            );

            const success = this.checkV2Response(response, status, 'setMode');
            if (success) {
                this.details.mode = targetMode;
                this.mode = targetMode;

                // Update cached speed snapshot for special modes
                if (targetMode === 'sleep') {
                    this.speed = 0;
                    this.details.speed = 0;
                } else if (targetMode === 'turbo') {
                    const maxSpeed = this.config.levels && this.config.levels.length > 0
                        ? Math.max(...this.config.levels)
                        : this.speed;
                    if (typeof maxSpeed === 'number' && maxSpeed > 0) {
                        this.speed = maxSpeed;
                        this.details.speed = maxSpeed;
                    }
                } else if (targetMode === 'auto') {
                    this.speed = 0;
                    this.details.speed = 0;
                    this.details.isAutoSentinel = true;
                }
                
                // Force a details update to sync state
                setTimeout(() => {
                    this.getDetails().catch(e => {
                        logger.debug(`Background state refresh failed: ${e}`);
                    });
                }, 1000);
                
                return true;
            } else {
                logger.error(`Failed to set mode to ${targetMode} for device: ${this.deviceName}`);
                return false;
            }
        } else {
            // Use parent implementation for non-bypassV2 models
            return super.setMode(mode);
        }
    }

    /**
     * Convenience helper to enter turbo mode when supported.
     */
    async turboMode(): Promise<boolean> {
        if (!this.modes.map(m => m.toLowerCase()).includes('turbo')) {
            logger.debug(`Turbo mode not supported for device: ${this.deviceName}`);
            return false;
        }
        return this.setMode('turbo');
    }

    /**
     * Convenience helper to enter pet mode when supported.
     */
    async petMode(): Promise<boolean> {
        if (!this.modes.map(m => m.toLowerCase()).includes('pet')) {
            logger.debug(`Pet mode not supported for device: ${this.deviceName}`);
            return false;
        }
        return this.setMode('pet');
    }

    /**
     * Override changeFanSpeed to use manualSpeedLevel for bypassV2 purifiers.
     */
    override async changeFanSpeed(speed: number): Promise<boolean> {
        const speeds = this.config.levels ?? [];
        if (speeds.length > 0 && !speeds.includes(speed)) {
            logger.error(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')} for device: ${this.deviceName}`);
            return false;
        }

        logger.info(`Changing fan speed to ${speed} for device: ${this.deviceName}`);
        
        const [head, body] = this.buildApiDict('setLevel');
        
        // Specific handling for bypassV2 devices
        if (this.requiresPowerSwitchPayload()) {
            logger.debug(`Using bypassV2 speed payload for ${this.deviceName}`);
            // For these devices, use levelIdx, levelType, and manualSpeedLevel per YAML spec
            body.payload.data = {
                levelIdx: 0,
                levelType: 'wind',
                manualSpeedLevel: speed
            };

            const [response, status] = await this.callApi(
                '/cloud/v2/deviceManaged/bypassV2',
                'post',
                body,
                head
            );

            const success = this.checkV2Response(response, status, 'changeFanSpeed');
            if (success) {
                this.speed = speed;
                this.details.manualSpeedLevel = speed;
                this.details.speed = speed;
                this.details.mode = 'manual';
                this.mode = 'manual';
                this.details.isAutoSentinel = false;
                
                // Force a details update to sync state
                setTimeout(() => {
                    this.getDetails().catch(e => {
                        logger.debug(`Background state refresh failed: ${e}`);
                    });
                }, 1000);
                
                return true;
            } else {
                logger.error(`Failed to change fan speed to ${speed} for device: ${this.deviceName}`);
                return false;
            }
        } else {
            // For non-bypassV2 models, use id, level, mode, and type
            body.payload.data = {
                id: 0,
                level: speed,
                mode: 'manual',
                type: 'wind'
            };

            const [response, status] = await this.callApi(
                '/cloud/v2/deviceManaged/bypassV2',
                'post',
                body,
                head
            );

            const success = this.checkResponse([response, status], 'changeFanSpeed');
            if (success) {
                this.speed = speed;
                this.details.manualSpeedLevel = speed;
                this.details.speed = speed;
                this.details.mode = 'manual';
                this.mode = 'manual';
                this.details.isAutoSentinel = false;
                return true;
            } else {
                logger.error(`Failed to change fan speed to ${speed} for device: ${this.deviceName}`);
                return false;
            }
        }
    }

    /**
     * Set auto preference
     */
    async setAutoPreference(preference: string = 'default', roomSize: number = 600): Promise<boolean> {
        if (!this.autoPreferences.includes(preference)) {
            logger.debug(`Invalid preference: ${preference} - valid preferences are ${this.autoPreferences.join(', ')}`);
            return false;
        }

        const [head, body] = this.buildApiDict('setAutoPreference');
        body.payload.data = {
            autoPreference: preference,
            roomSize: roomSize
        };

        const [response, status] = await this.callApi(
            '/cloud/v2/deviceManaged/bypassV2',
            'post',
            body,
            head
        );

        // Use the appropriate response checking method based on device type
        const success = this.requiresPowerSwitchPayload() 
            ? this.checkV2Response(response, status, 'setAutoPreference')
            : this.checkResponse([response, status], 'setAutoPreference');
            
        if (success) {
            this.details.auto_preference = preference;
            this.details.auto_preference_type = preference;
            
            // Force a details update to sync state for bypassV2 purifiers
            if (this.requiresPowerSwitchPayload()) {
                setTimeout(() => {
                    this.getDetails().catch(e => {
                        logger.debug(`Background state refresh failed: ${e}`);
                    });
                }, 1000);
            }
        }
        return success;
    }

    /**
     * Set light detection
     */
    async setLightDetection(enabled: boolean): Promise<boolean> {
        const [head, body] = this.buildApiDict('setLightDetection');
        body.payload.data = {
            lightDetectionSwitch: enabled ? 1 : 0
        };

        const [response, status] = await this.callApi(
            '/cloud/v2/deviceManaged/bypassV2',
            'post',
            body,
            head
        );

        // Use the appropriate response checking method based on device type
        const success = this.requiresPowerSwitchPayload()
            ? this.checkV2Response(response, status, 'setLightDetection')
            : this.checkResponse([response, status], 'setLightDetection');
            
        if (success) {
            this.details.light_detection_switch = enabled;
            
            // Force a details update to sync state for bypassV2 purifiers
            if (this.requiresPowerSwitchPayload()) {
                setTimeout(() => {
                    this.getDetails().catch(e => {
                        logger.debug(`Background state refresh failed: ${e}`);
                    });
                }, 1000);
            }
        }
        return success;
    }

    /**
     * Get light detection status
     */
    get lightDetection(): boolean {
        return Boolean(this.details.light_detection_switch);
    }

    /**
     * Get light detection state
     */
    get lightDetectionState(): boolean {
        return Boolean(this.details.environment_light_state);
    }

    /**
     * Get auto preference type
     */
    get autoPreferenceType(): string | null {
        return this.details.auto_preference_type;
    }

    /**
     * Display JSON details
     */
    override displayJSON(): string {
        const baseInfo = JSON.parse(super.displayJSON());
        const details: Record<string, string> = {
            ...baseInfo,
            'Mode': this.mode,
            'Filter Life': (this.details.filter_life ?? 0).toString(),
            'Fan Level': this.speed.toString(),
            'Display On': this.details.display?.toString() ?? 'false',
            'Child Lock': (this.details.child_lock ?? false).toString(),
            'Night Light': (this.details.night_light ?? '').toString(),
            'Display Set On': (this.details.screen_switch ?? false).toString(),
            'Light Detection Enabled': (this.details.light_detection_switch ?? false).toString(),
            'Environment Light State': (this.details.environment_light_state ?? false).toString()
        };

        if (this.hasFeature('air_quality')) {
            details['Air Quality Level'] = (this.details.air_quality ?? '').toString();
            details['Air Quality Value'] = (this.details.air_quality_value ?? '').toString();
        }

        const everestKeys: Record<string, string> = {
            'pm1': 'PM1',
            'pm10': 'PM10',
            'fan_rotate_angle': 'Fan Rotate Angle',
            'filter_open_state': 'Filter Open State'
        };

        for (const [key, value] of Object.entries(everestKeys)) {
            if (key in this.details) {
                details[value] = this.details[key]?.toString() ?? '';
            }
        }

        return JSON.stringify(details, null, 4);
    }

    /**
     * Set oscillation state
     */
    async setOscillation(toggle: boolean): Promise<boolean> {
        logger.debug(`Setting oscillation to ${toggle ? 'on' : 'off'} for device: ${this.deviceName}`);
        
        const [head, body] = this.buildApiDict('setSwitch');
        body.payload.data = {
            oscillationSwitch: toggle ? 1 : 0,
            switchIdx: 0
        };

        const [response, status] = await this.callApi(
            '/cloud/v2/deviceManaged/bypassV2',
            'post',
            body,
            head
        );

        // Use the appropriate response checking method based on device type
        const success = this.requiresPowerSwitchPayload()
            ? this.checkV2Response(response, status, 'setOscillation')
            : this.checkResponse([response, status], 'setOscillation');
            
        if (success) {
            this.details.oscillationState = toggle;
            this.details.oscillationSwitch = toggle ? 1 : 0;
        }
        return success;
    }
}
