import { SDK_VERSION } from '../../utils/constants';
import { isRealDevice } from '../../utils/native-helper';
import * as types from '../../utils/types';
import * as domainDebugger from '../../debugger';
import { getFilenameFromUrl } from './http-request-common';
import { ImageSource } from '../../image-source';
import { File } from '../../file-system';
import { HttpResponseEncoding } from '../http-interfaces';
const currentDevice = UIDevice.currentDevice;
const device = currentDevice.userInterfaceIdiom === 0 /* UIUserInterfaceIdiom.Phone */ ? 'Phone' : 'Pad';
const osVersion = currentDevice.systemVersion;
const GET = 'GET';
const USER_AGENT_HEADER = 'User-Agent';
const USER_AGENT = `Mozilla/5.0 (i${device}; CPU OS ${osVersion.replace('.', '_')} like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/${osVersion} Mobile/10A5355d Safari/8536.25`;
// mitigate iOS 18.4 simulator regression
// https://developer.apple.com/forums/thread/777999
const sessionConfig = SDK_VERSION === 18.4 && !isRealDevice() ? NSURLSessionConfiguration.ephemeralSessionConfiguration : NSURLSessionConfiguration.defaultSessionConfiguration;
const queue = NSOperationQueue.mainQueue;
function parseJSON(source) {
    const src = source.trim();
    if (src.lastIndexOf(')') === src.length - 1) {
        return JSON.parse(src.substring(src.indexOf('(') + 1, src.lastIndexOf(')')));
    }
    return JSON.parse(src);
}
var NSURLSessionTaskDelegateImpl = (function (_super) {
    __extends(NSURLSessionTaskDelegateImpl, _super);
    function NSURLSessionTaskDelegateImpl() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    NSURLSessionTaskDelegateImpl.prototype.URLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandler = function (session, task, response, request, completionHandler) {
        completionHandler(null);
    };
    NSURLSessionTaskDelegateImpl.ObjCProtocols = [NSURLSessionTaskDelegate];
    return NSURLSessionTaskDelegateImpl;
}(NSObject));
const sessionTaskDelegateInstance = NSURLSessionTaskDelegateImpl.new();
let defaultSession;
function ensureDefaultSession() {
    if (!defaultSession) {
        defaultSession = NSURLSession.sessionWithConfigurationDelegateDelegateQueue(sessionConfig, null, queue);
    }
}
let sessionNotFollowingRedirects;
function ensureSessionNotFollowingRedirects() {
    if (!sessionNotFollowingRedirects) {
        sessionNotFollowingRedirects = NSURLSession.sessionWithConfigurationDelegateDelegateQueue(sessionConfig, sessionTaskDelegateInstance, queue);
    }
}
export function request(options) {
    return new Promise((resolve, reject) => {
        if (!options.url) {
            reject(new Error('Request url was empty.'));
            return;
        }
        try {
            const network = domainDebugger.getNetwork();
            const debugRequest = network && network.create();
            const urlRequest = NSMutableURLRequest.requestWithURL(NSURL.URLWithString(options.url));
            urlRequest.HTTPMethod = types.isDefined(options.method) ? options.method : GET;
            urlRequest.setValueForHTTPHeaderField(USER_AGENT, USER_AGENT_HEADER);
            if (options.headers) {
                for (const header in options.headers) {
                    urlRequest.setValueForHTTPHeaderField(options.headers[header] + '', header);
                }
            }
            if (types.isString(options.content) || options.content instanceof FormData) {
                urlRequest.HTTPBody = NSString.stringWithString(options.content.toString()).dataUsingEncoding(4);
            }
            else if (options.content instanceof ArrayBuffer) {
                const buffer = options.content;
                urlRequest.HTTPBody = NSData.dataWithData(buffer);
            }
            if (types.isNumber(options.timeout)) {
                urlRequest.timeoutInterval = options.timeout / 1000;
            }
            let session;
            if (types.isBoolean(options.dontFollowRedirects) && options.dontFollowRedirects) {
                ensureSessionNotFollowingRedirects();
                session = sessionNotFollowingRedirects;
            }
            else {
                ensureDefaultSession();
                session = defaultSession;
            }
            let timestamp = -1;
            const dataTask = session.dataTaskWithRequestCompletionHandler(urlRequest, function (data, response, error) {
                if (error) {
                    reject(new Error(error.localizedDescription));
                }
                else {
                    const headers = {};
                    if (response && response.allHeaderFields) {
                        const headerFields = response.allHeaderFields;
                        headerFields.enumerateKeysAndObjectsUsingBlock((key, value, stop) => {
                            addHeader(headers, key, value);
                        });
                    }
                    if (debugRequest) {
                        debugRequest.mimeType = response.MIMEType;
                        debugRequest.data = data;
                        const debugResponse = {
                            url: options.url,
                            status: response.statusCode,
                            statusText: NSHTTPURLResponse.localizedStringForStatusCode(response.statusCode),
                            headers: headers,
                            mimeType: response.MIMEType,
                            fromDiskCache: false,
                            timing: {
                                requestTime: timestamp,
                                proxyStart: -1,
                                proxyEnd: -1,
                                dnsStart: -1,
                                dnsEnd: -1,
                                connectStart: -1,
                                connectEnd: -1,
                                sslStart: -1,
                                sslEnd: -1,
                                serviceWorkerFetchStart: -1,
                                serviceWorkerFetchReady: -1,
                                serviceWorkerFetchEnd: -1,
                                sendStart: -1,
                                sendEnd: -1,
                                receiveHeadersEnd: -1,
                            },
                            headersSize: headers?.length ?? -1,
                        };
                        debugRequest.responseReceived(debugResponse);
                        debugRequest.loadingFinished();
                    }
                    resolve({
                        content: {
                            raw: data,
                            toArrayBuffer: () => interop.bufferFromData(data),
                            toString: (encoding) => {
                                const str = NSDataToString(data, encoding);
                                if (typeof str === 'string') {
                                    return str;
                                }
                                else {
                                    throw new Error('Response content may not be converted to string');
                                }
                            },
                            toJSON: (encoding) => parseJSON(NSDataToString(data, encoding)),
                            toImage: () => {
                                return new Promise((resolve, reject) => {
                                    UIImage.tns_decodeImageWithDataCompletion(data, (image) => {
                                        if (image) {
                                            resolve(new ImageSource(image));
                                        }
                                        else {
                                            reject(new Error('Response content may not be converted to an Image'));
                                        }
                                    });
                                });
                            },
                            toFile: (destinationFilePath) => {
                                if (!destinationFilePath) {
                                    destinationFilePath = getFilenameFromUrl(options.url);
                                }
                                if (data instanceof NSData) {
                                    // ensure destination path exists by creating any missing parent directories
                                    const file = File.fromPath(destinationFilePath);
                                    data.writeToFileAtomically(destinationFilePath, true);
                                    return file;
                                }
                                else {
                                    reject(new Error(`Cannot save file with path: ${destinationFilePath}.`));
                                }
                            },
                        },
                        statusCode: response.statusCode,
                        headers: headers,
                    });
                }
            });
            if (options.url && debugRequest) {
                timestamp = Date.now() / 1000;
                const request = {
                    url: options.url,
                    method: 'GET',
                    headers: options.headers,
                    timestamp,
                    headersSize: options?.headers?.length ?? -1,
                };
                debugRequest.requestWillBeSent(request);
            }
            dataTask.resume();
        }
        catch (ex) {
            reject(ex);
        }
    });
}
function NSDataToString(data, encoding) {
    let code = NSUTF8StringEncoding; // long:4
    if (encoding === HttpResponseEncoding.GBK) {
        code = 1586 /* CFStringEncodings.kCFStringEncodingGB_18030_2000 */; // long:1586
    }
    let encodedString = NSString.alloc().initWithDataEncoding(data, code);
    // If UTF8 string encoding fails try with ISO-8859-1
    if (!encodedString) {
        code = NSISOLatin1StringEncoding; // long:5
        encodedString = NSString.alloc().initWithDataEncoding(data, code);
    }
    return encodedString.toString();
}
export function addHeader(headers, key, value) {
    if (!headers[key]) {
        headers[key] = value;
    }
    else if (Array.isArray(headers[key])) {
        headers[key].push(value);
    }
    else {
        const values = [headers[key]];
        values.push(value);
        headers[key] = values;
    }
}
//# sourceMappingURL=index.ios.js.map