import axios from 'axios';

class BoxApi {

    private readonly defaultPort: number = 8000;

    private readonly apiLogin: string = "/auth/login";
    private readonly apiLogout: string = "/auth/logout";
    private readonly apiAdduser: string = "/auth/adduser";
    private readonly apiRmuser: string = "/auth/rmuser";
    private readonly apiAllusers: string = "/auth/allusers";
    private readonly apiCameras: string = "/cameras";
    private readonly apiEvents: string = "/events";
    private readonly apiAlgorithms: string = "/algorithms";
    private readonly apiResetUser: string = "/auth/resetuser";
    private readonly apiResetPassword: string = "/auth/reset_password";
    private readonly getMinCamerasApi: string = "/camera/cameras/get_all";
    private readonly getMinCamera: string = "/camera/cameras";

    private readonly loginConfig: object = {
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        }
    }

    private address: string = "";
    private port: number = this.defaultPort;
    private token: string = "";

    private codemap: Map<string, string> = new Map<string, string>();
    private axios: any = null;

    public constructor(
        address: string = "",
        port: number = 0
    ) {
        // 获取本地存储的address和port
        const rememberedAddress = localStorage.getItem('rememberedAddress') || '127.0.0.1';
        const rememberedPort = localStorage.getItem('rememberedPort') || '8000';

        this.setAddress(address || rememberedAddress);
        this.setPort(port || parseInt(rememberedPort));

        // 动态创建axios实例，基于当前的address和port
        this.createAxiosInstance();
    }

    private createAxiosInstance() {
        // 动态生成baseURL
        this.axios = axios.create({
            baseURL: `http://${this.address}:${this.port}/api/v1`,
            withCredentials: true
        });
    }

    public setAddress(address: string) {
        this.address = address === "" ? this._boxAddr() : address;
        this.createAxiosInstance();
    }

    public setPort(port: number) {
        this.port = port === 0 ? this.defaultPort : port;
        this.createAxiosInstance();
    }

    public setToken(token: string) {
        this.token = token;
    }

    public async login(username: string, password: string, cookieLess: boolean = false): Promise<any> {
        const loginData = {
            username: username,
            password: password,
            cookieless: cookieLess ? "True" : "False"
        };

        try {
            const res = await this.axios.post(this.apiLogin, loginData, this.loginConfig)
            console.log(res)
            if (res.data.err.ec === 0) {
                this.token = res.data.ret.token;
                await this.updateCodemap(this.token);
                return res.data.ret.token;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    public async logout(token: string | null = null): Promise<any> {
        try {
            const res = await this.axios.post(this.apiLogout, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }


    public async resetPassword(newPassword: string, token: string | null = null): Promise<any> {
        try {
            const data = {
                new_password: newPassword
            };

            const res = await this.axios.post(this.apiResetPassword, data, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    public async resetUser(username: string, password: string, email: string, token: string | null = null): Promise<any> {
        try {
            const data = {
                username: username,
                password: password,
                email: email
            };

            const res = await this.axios.post(this.apiResetUser, data, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    public async addUser(username: string, password: string, email: string = "", token: string | null = null): Promise<any> {
        try {
            const data = {
                username: username,
                password: password,
                email: email
            };

            const res = await this.axios.post(this.apiAdduser, data, this._authHeader(token));

            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw res.data.err;
            }
        } catch (error: any) {
            if (error.response && error.response.data && error.response.data.err) {
                throw error.response.data.err;
            } else {
                throw new Error("网络错误或服务器未响应");
            }
        }
    }

    public async rmUser(username: string, token: string | null = null): Promise<any> {
        try {
            const data = {
                username: username
            };

            const res = await this.axios.post(this.apiRmuser, data, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    public async getAllUsers(token: string | null = null): Promise<any> {
        try {
            const res = await this.axios.get(this.apiAllusers, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data.ret.users;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    public async getCamerasByUrl(url: string, token: string | null = null): Promise<any> {
        try {
            const res = await this.axios.get(url, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    public async getCameras(limit: number, offset: number, token: string | null = null): Promise<any> {
        const url = `${this.apiCameras}?limit=${limit}&offset=${offset}`;
        return await this.getCamerasByUrl(url, token);
    }

    public async getMinCameras(token: string | null = null): Promise<any> {
        const url = `${this.getMinCamerasApi}`;
        try {
            const res = await this.axios.get(url, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    public async startCameraStream(token: string | null = null, cameraId: number): Promise<any> {
        const url = `${this.getMinCamera}/${cameraId}/start_stream`;
        try {
            const res = await this.axios.post(url, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    public async stopCameraStream(token: string | null = null, cameraId: number): Promise<any> {
        const url = `${this.getMinCamera}/${cameraId}/stop_stream`;
        try {
            const res = await this.axios.post(url, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw new Error(res.data.err.dm);
            }
        } catch (error) {
            throw error;
        }
    }

    public async getEventsByUrl(url: string, token: string | null = null): Promise<any> {
        try {
            const res = await this.axios.get(url, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    // public async getEvents(limit: number, offset: number, token: string | null = null): Promise<any> {
    //     const url = `${this.apiEvents}?limit=${limit}&offset=${offset}`;
    //     return await this.getEventsByUrl(url, token);
    // }

    // public async getEvents(token: string | null = null, pageSize: number = 10, currentPage: number = 1): Promise<any> {
    //     const offset = (currentPage - 1) * pageSize;

    //     const url = `${this.apiEvents}?limit=${pageSize}&offset=${offset}`;

    //     try {
    //         const res = await this.axios.get(url, this._authHeader(token));
    //         if (res.data.err.ec === 0) {
    //             return res.data.ret;
    //         } else {
    //             throw new Error(res.data.err.msg);
    //         }
    //     } catch (error) {
    //         throw error;
    //     }
    // }

    public async getEvents(token: string | null = null, pageSize: number = 20, currentPage: number = 1): Promise<any> {
        // 计算 offset
        const offset = (currentPage - 1) * pageSize;

        try {
            // 发送请求，携带 limit 和 offset 参数
            const res = await this.axios.get(`${this.apiEvents}?limit=${pageSize}&offset=${offset}`, this._authHeader(token));

            // 请求成功，返回数据
            if (res.data.err.ec === 0) {
                return {
                    tableData: res.data.ret.results,   // 告警数据
                    totalItems: res.data.ret.count     // 总条数
                };
            } else {
                // 处理请求失败情况
                throw new Error(res.data.err);
            }
        } catch (error) {
            // 抛出异常以便前端捕获
            throw error;
        }
    }

    public async getEventsByParams(
        token: string | null = null,
        pageSize: number = 20,
        currentPage: number = 1,
        timeBefore: string | null = null,
        timeAfter: string | null = null,
        types: string | null = null,
        camera_id: number | null = null,
        status?: 'pending' | 'closed' | null
    ): Promise<any> {
        // 计算 offset
        const offset = (currentPage - 1) * pageSize;

        // 构建请求的 URL
        let url = `${this.apiEvents}?limit=${pageSize}&offset=${offset}`;

        // 如果有时间范围，则添加到 URL 中
        if (timeBefore && timeAfter) {
            url += `&time_before=${encodeURIComponent(timeBefore)}&time_after=${encodeURIComponent(timeAfter)}`;
        }

        // 如果 types 不为空，则添加到 URL 中
        if (types) {
            url += `&types=${encodeURIComponent(types)}`;
        }
        if(camera_id){
            url += `&camera_id=${camera_id}`;
        }
        if (status) {
            url += `&status=${encodeURIComponent(status)}`;
        }

        try {
            // 发送 GET 请求
            const res = await this.axios.get(url, this._authHeader(token));

            // 判断请求是否成功
            if (res.data.err.ec === 0) {
                return {
                    count: res.data.ret.count,
                    next: res.data.ret.next,
                    previous: res.data.ret.previous,
                    results: res.data.ret.results
                };
            } else {
                // 处理请求失败的情况
                throw new Error(res.data.err.dm);
            }
        } catch (error) {
            // 抛出异常以便调用者处理
            throw error;
        }
    }
    // public async getOneEvent(token: string | null = null): Promise<any> {
    //     try {
    //         return await this.getEvents(1, 0, token);
    //     } catch (error) {
    //         throw error;
    //     }
    // }
    public async getOneEvent(token: string | null = null): Promise<any> {
        try {
            // 调用 getEvents 方法，设置 pageSize 为 1，currentPage 为 1
            return await this.getEvents(token, 1, 1);
        } catch (error) {
            throw error;
        }
    }

    public async setEventStatus(eventId: number, status: string, remark: string | null = null, token: string | null = null): Promise<any> {
        const url = `${this.apiEvents}/${eventId}`;
    
        
        const data: { status: string; remark?: string } = { status: status };
        if (remark && remark.trim() !== "") {
            data.remark = remark;
        }
    
        try {
            const res = await this.axios.patch(url, data, this._authHeader(token));
            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    public async getAlgorithms(token: string | null = null): Promise<any> {
        try {
            const res = await this.axios.get(this.apiAlgorithms, this._authHeader(token))
            if (res.data.err.ec === 0) {
                return res.data.ret;
            } else {
                throw new Error(res.data.err.msg);
            }
        } catch (error) {
            throw error;
        }
    }

    public async updateCodemap(token: string | null = null): Promise<boolean> {
        try {
            this.codemap.clear()
            const algorithms = await this.getAlgorithms(token);
            algorithms.forEach((algorithm: { code_name: string, name: string }) => {
                this.codemap.set(algorithm.code_name, algorithm.name)
            });
            return true;
        } catch (error) {
            return false;
        }
    }

    public getAlgorithmName(code_name: string): string {
        return this.codemap.get(code_name) || code_name;
    }

    private _authHeader(token: string | null = null): object {
        const accessToken = token || this.token || localStorage.getItem('alertToken') || "";
        return {
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'Authorization': `Bearer ${accessToken}`,
                // 'X-CSRFToken': this.getCsrfToken() 
            }
        };
    }
    private getCsrfToken(): string {
        const cookie = document.cookie.split(';').find(cookie => cookie.trim().startsWith('csrftoken='));
        if (cookie) {
            return cookie.split('=')[1];
        }
        return '';
    }


    private _boxAddr() {
        return window.location.host.replace(/:\d+/, "");
    }

}

export { BoxApi };
