import { HttpClient, HttpParams, HttpHeaders, HttpEventType } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { lastValueFrom, map, BehaviorSubject, Observable, firstValueFrom } from 'rxjs';

export interface EverythingResult {
    files: FileItem[];
    total: number;
    pageIndex: number;
    pageSize: number;
}

export interface FileItem {
    name: string;
    path: string;
    size: number;
    dateModified: Date;
    dateCreated: Date;
    isDirectory: boolean;
    extension?: string;
}

export interface AuthCredentials {
    username: string;
    password: string;
    recaptcha?: string;
}

export interface AuthResponse {
    token: string;
    refreshToken?: string;
    expiresIn?: number;
}

export interface DirectoryContent {
    path: string;
    files: FileItem[];
    directories: FileItem[];
    parent?: string;
}

export interface FileUploadProgress {
    progress: number;
    status: 'uploading' | 'completed' | 'error';
}

@Injectable()
export class FileBrowserService {
    private baseUrl = 'https://fikoyt.com:9000/uyar/admin/filebrowser/api-all';
    private everythingUrl = 'http://127.0.0.1:7777';
    private fileBrowserUrl = `https://fikoyt.com:9000/uyar/admin/filebrowser/api-all`;
    private fileBrowserLoginUrl = `https://fikoyt.com:9000/uyar/admin/filebrowser/login`;

    private authToken$ = new BehaviorSubject<string | null>(null);
    private isAuthenticated$ = new BehaviorSubject<boolean>(false);

    private pageIndex = 1;
    private pageSize = 5;
    private query = '*.nc';

    private currentPath$ = new BehaviorSubject<string>('');

    constructor(private http: HttpClient) {
        this.loadAuthToken();
        this.initializeAuth();
    }

    private async initializeAuth(): Promise<void> {
        try {
            await this.Uyarlogin();
            const rslt = await this.listDirectory();
            console.log('Directory listed:', rslt);
        } catch (error) {
            console.error('Auth initialization error:', error);
        }
    }

    async login(credentials: AuthCredentials): Promise<any> {
        const response = await lastValueFrom(
            this.http.post(`${this.fileBrowserLoginUrl}`, credentials, {
                withCredentials: true,
                responseType: 'text'
            })
        );
        this.setAuthToken(response);
        return response;
    }

    async Uyarlogin(): Promise<void> {
        try {
            await this.login({
                username: "admin",
                password: "admin123456789",
                recaptcha: ""
            });
        } catch (error: any) {
            console.error('Login error:', error);
        }
    }

    logout(): void {
        this.clearAuthToken();
    }

    async refreshToken(): Promise<AuthResponse> {
        const headers = this.getAuthHeaders();
        const response = await lastValueFrom(
            this.http.post<AuthResponse>(`${this.baseUrl}/api/renew`, {}, {
                headers,
                withCredentials: true
            })
        );
        this.setAuthToken(response.token);
        return response;
    }

    isAuthenticatedObs(): Observable<boolean> {
        return this.isAuthenticated$.asObservable();
    }

    getToken(): string | null {
        return this.authToken$.value;
    }

    private setAuthToken(token: string): void {
        localStorage.setItem('auth_token', token);
        this.authToken$.next(token);
        this.isAuthenticated$.next(true);
    }

    private clearAuthToken(): void {
        localStorage.removeItem('auth_token');
        this.authToken$.next(null);
        this.isAuthenticated$.next(false);
    }

    private loadAuthToken(): void {
        const token = localStorage.getItem('auth_token');
        if (token) {
            this.authToken$.next(token);
            this.isAuthenticated$.next(true);
        }
    }

    private getAuthHeaders(): HttpHeaders {
        const token = this.authToken$.value;
        return new HttpHeaders({
            'Accept': 'application/json',
            'X-Auth': `${token}`,
        });
    }

    async search(query?: string, pageIndex?: number, pageSize?: number): Promise<EverythingResult> {
        if (query !== undefined) this.query = query;
        if (pageIndex !== undefined) this.pageIndex = pageIndex;
        if (pageSize !== undefined) this.pageSize = pageSize;

        const params = new HttpParams()
            .set('search', this.query)
            .set('c', this.pageSize.toString())
            .set('p', this.pageIndex.toString())
            .set('o', (this.pageIndex * this.pageSize).toString())
            .set('j', '1')
            .set('i', '0')
            .set('w', '0')
            .set('r', '0')
            .set('m', '1')
            .set('path_column', '1')
            .set('date_created_column', '1')
            .set('size_column', '1')
            .set('date_modified_column', '1')
            .set('sort', 'date_modified')
            .set('ascending', '0');

        const headers = this.getAuthHeaders();

        const obs$ = this.http.get<any>(this.everythingUrl, { params, headers }).pipe(
            map((res) => {
                const files = (res?.results || []).map((item: any) => this.parseFileItem(item));
                return {
                    files,
                    total: res?.totalResults || 0,
                    pageIndex: this.pageIndex,
                    pageSize: this.pageSize,
                } as EverythingResult;
            })
        );

        return await lastValueFrom(obs$);
    }

    async listDirectory(path: string = 'Masaustu-2025/POSTLAR'): Promise<DirectoryContent> {
        const params = new HttpParams().set('path', path);
        const headers = this.getAuthHeaders();

        const response = await lastValueFrom(
            this.http.get<any>(`${this.fileBrowserUrl}/api/resources/${path}`, {
                params,
                headers,
                withCredentials: true
            })
        );

        this.currentPath$.next(path);

        return {
            path: response.path || path,
            files: (response.items || []).map((item: any) => this.parseFileItem(item)),
            directories: (response.directories || []).map((item: any) => this.parseFileItem(item)),
            parent: response.parent
        };
    }

    async postYolla(fileOrBlob: Blob, dosyaIsmi: string, onProgress: (progress: number) => void): Promise<any> {
        const token = this.getToken();
        const url = `${this.fileBrowserUrl}/api/tus/Masaustu-2025/POSTLAR/${dosyaIsmi}`;

        const headersPost = new HttpHeaders({
            'tus-resumable': '1.0.0',
            'upload-length': fileOrBlob.size.toString(),
            'x-auth': token,
            'Authorization': `Bearer ${token}`,
        });

        await lastValueFrom(
            this.http.post(url, null, { headers: headersPost, observe: 'response', responseType: 'text' })
        );

        const offset = await this.getOffset(dosyaIsmi, token!);
        const chunk = fileOrBlob.slice(offset);

        const headersPatch = new HttpHeaders({
            'tus-resumable': '1.0.0',
            'upload-offset': offset.toString(),
            'x-auth': token,
            'Authorization': `Bearer ${token}`,
            'Content-Type': 'application/offset+octet-stream',
        });

        return new Promise((resolve, reject) => {
            this.http.patch(url, chunk, {
                headers: headersPatch,
                observe: 'events',
                reportProgress: true,
                responseType: 'text'
            }).subscribe({
                next: (event) => {
                    if (event.type === HttpEventType.UploadProgress) {
                        const progress = Math.round((event.loaded / event.total!) * 100);
                        onProgress(progress);
                    } else if (event.type === HttpEventType.Response) {
                        resolve(event.body);
                    }
                },
                error: (err) => reject(err)
            });
        });
    }

    async getOffset(dosyaIsmi: string, token: string): Promise<number> {
        const url = `${this.fileBrowserUrl}/api/tus/Masaustu-2025/POSTLAR/${dosyaIsmi}`;
        const headers = new HttpHeaders({
            'x-auth': token,
            'Authorization': `Bearer ${token}`,
        });

        const response = await firstValueFrom(
            this.http.head(url, { headers, observe: 'response' })
        );

        const offset = response.headers.get('upload-offset');
        return offset ? parseInt(offset, 10) : 0;
    }

    async postSil(dosyaIsmi: string): Promise<any> {
        const headers = this.getAuthHeaders();
        return await lastValueFrom(
            this.http.delete(`${this.fileBrowserUrl}/api/resources/Masaustu-2025/POSTLAR/${dosyaIsmi}`, {
                headers
            })
        );
    }

    async postKopyala(dosyaTamYolu: string, dosyaIsmi: string): Promise<any> {
        const headersPatch = new HttpHeaders({
            'X-Auth': this.getToken(),
            'Authorization': `Bearer ${this.getToken()}`,
            'Content-Type': 'application/offset+octet-stream',
        });
        return await lastValueFrom(
            this.http.patch(`${this.fileBrowserUrl}/api/resources/${dosyaTamYolu}?action=copy&destination=${encodeURI('/Masaustu-2025/POSTLAR/' + dosyaIsmi)}&override=false&rename=false`, null, {
                headers: headersPatch,
                withCredentials: true,
            })
        );
    }

    getCurrentPath(): Observable<string> {
        return this.currentPath$.asObservable();
    }

    private parseFileItem(item: any): FileItem {
        const filetimeToDate = (ft?: any) => {
            if (ft === undefined) return undefined;

            if (typeof ft === "string") {
                if (/^\d+$/.test(ft)) {
                    const filetimeBigInt = BigInt(ft);
                    return new Date(Number(filetimeBigInt / 10000n - 11644473600000n));
                } else if (!isNaN(Date.parse(ft))) {
                    return new Date(ft);
                } else {
                    return ft;
                }
            }

            if (typeof ft === "number" || typeof ft === "bigint") {
                const filetimeBigInt = typeof ft === "bigint" ? ft : BigInt(ft);
                return new Date(Number(filetimeBigInt / 10000n - 11644473600000n));
            }

            return ft;
        };

        return {
            name: item.name || '',
            path: item.path || '',
            size: item.size || 0,
            dateModified: filetimeToDate(item.modified ?? item.date_modified),
            dateCreated: filetimeToDate(item.modified ?? item.date_modified),
            isDirectory: item.type === 'directory' || item.isDirectory || false,
            extension: item.extension || this.getExtension(item.name || '')
        };
    }

    private getExtension(filename: string): string {
        const parts = filename.split('.');
        return parts.length > 1 ? parts.pop()! : '';
    }

    formatFileSize(bytes: number): string {
        if (bytes === 0) return '0 Bytes';
        const k = 1024;
        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
    }
}
