import { Component, DestroyRef, inject } from '@angular/core';
import {
  MatDialogModule,
  MatDialogRef,
  MAT_DIALOG_DATA
} from '@angular/material/dialog';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatIconModule } from '@angular/material/icon';
import { MatCardModule } from '@angular/material/card';
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatInputModule } from '@angular/material/input';
import { AppFacade } from 'src/app/app.facade';
import { SKChart } from 'src/app/modules/skresources/resource-classes';
import { ChartProvider } from 'src/app/types';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

interface MapboxStyle {
  version: string;
  name?: string;
  sources: Array<{
    [index: string]: {
      type: string;
      url: string;
    };
  }>;
  layers: Array<{
    id: string;
    source: string;
    'source-layer': string;
  }>;
}

interface TileJson {
  tilejson: string;
  name: string;
  description: string;
  vector_layers?: Array<{
    id: string;
    description: string;
  }>;
  maxzoom: number;
  minzoom: number;
  bounds: [number, number, number, number];
  id: string;
}

@Component({
  selector: 'json-mapsource-dialog',
  imports: [
    MatTooltipModule,
    MatIconModule,
    MatCardModule,
    MatButtonModule,
    MatToolbarModule,
    MatDialogModule,
    MatProgressBarModule,
    MatInputModule
  ],
  template: `
    <div class="_ap-mapbox">
      <mat-toolbar style="background-color: transparent">
        <span class="dialog-icon"><mat-icon>public</mat-icon></span>
        <span style="flex: 1 1 auto; text-align: center"
          >Add JSON Map Source</span
        >
        <span style="text-align: right">
          <button mat-icon-button (click)="dialogRef.close()">
            <mat-icon>close</mat-icon>
          </button>
        </span>
      </mat-toolbar>
      <mat-dialog-content>
        <mat-form-field floatLabel="always" style="width:100%">
          <mat-label> Map Server host. </mat-label>
          <input matInput #txturl type="url" required [(value)]="hostUrl" />
          @if (txturl) {
            <button
              matSuffix
              mat-icon-button
              [disabled]="txturl.value.length === 0"
              (click)="getJsonFile(txturl.value)"
            >
              <mat-icon>arrow_forward</mat-icon>
            </button>
          }
          <mat-hint> Enter url of the Map Server. </mat-hint>
          @if (txturl.invalid) {
            <mat-error>Map server host url is required!</mat-error>
          }
        </mat-form-field>
        @if (isFetching) {
          <mat-progress-bar mode="query"></mat-progress-bar>
        } @else {
          @if (errorMsg) {
            <mat-error>Error retrieving data from server!</mat-error>
          } @else {
            <div>
              @if (provider) {
                <br />
                <div style="height: 200px;overflow-x: hidden;overflow-y: auto;">
                  <div class="row">
                    <div class="label">Source:</div>
                    <div class="value">{{ details.type }}</div>
                  </div>
                  <div class="row">
                    <div class="label">Name:</div>
                    <div class="value">{{ details.name }}</div>
                  </div>
                  <div class="row">
                    <div class="label">Version:</div>
                    <div class="value">{{ details.version }}</div>
                  </div>
                  <div class="row">
                    <div class="label">Layers:</div>
                    <div class="value">
                      @for (l of details.layers; track l) {
                        <div>{{ l }}</div>
                      }
                    </div>
                  </div>
                </div>
              }
            </div>
          }
        }
      </mat-dialog-content>
      @if (provider) {
        <mat-dialog-actions align="right">
          <button mat-raised-button (click)="handleSave()">Save</button>
        </mat-dialog-actions>
      }
    </div>
  `,
  styles: [
    `
      ._ap-mapbox {
      }
      ._ap-mapbox .row {
        display: flex;
      }
      ._ap-mapbox .label {
        width: 70px;
        font-weight: 500;
      }
      ._ap-mapbox .value {
        flex: 1 1 auto;
      }
    `
  ]
})
export class JsonMapSourceDialog {
  protected isFetching = false;
  protected fetchError = false;
  protected errorMsg = '';
  protected hostUrl = '';
  protected provider!: ChartProvider;
  protected details: {
    type: string;
    name: string;
    version: string;
    layers: string[];
  };

  protected app = inject(AppFacade);
  protected dialogRef = inject(MatDialogRef<JsonMapSourceDialog>);
  private http = inject(HttpClient);
  protected data = inject<SKChart>(MAT_DIALOG_DATA);
  private destroyRef = inject(DestroyRef);

  constructor() {}

  handleSave() {
    this.dialogRef.close([this.provider]);
  }

  /** Fetch the mapbox JSON file contents */
  getJsonFile(uri: string) {
    this.errorMsg = '';
    this.fetchError = false;
    this.isFetching = true;
    this.provider = undefined;

    this.http
      .get(uri)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: (res: TileJson | MapboxStyle) => {
          this.isFetching = false;
          if (!res.name) {
            this.errorMsg = 'Invalid response received!';
          } else {
            const c = this.parseFileContents(res, uri);
            if (c) {
              this.provider = c as ChartProvider;
              this.details = {
                type: (res as TileJson).tilejson ? 'TileJSON' : 'Mapbox Style',
                name: res.name,
                version: (res as MapboxStyle).version
                  ? (res as MapboxStyle).version
                  : (res as TileJson).tilejson,
                layers: (res as MapboxStyle).layers
                  ? (res as MapboxStyle).layers.map((l) => l.id)
                  : (res as TileJson).vector_layers
                    ? (res as TileJson).vector_layers.map((l) => l.id)
                    : []
              };
              this.dialogRef.close([this.provider]);
            } else {
              this.fetchError = true;
              this.errorMsg = 'Invalid file contents!';
            }
          }
        },
        error: (err: HttpErrorResponse) => {
          this.isFetching = false;
          this.fetchError = true;
          this.errorMsg = err.message;
        }
      });
  }

  parseFileContents(json: TileJson | MapboxStyle, uri: string): ChartProvider {
    if ('tilejson' in json) {
      return {
        name: json.name ?? '',
        description: json.description ?? '',
        type: 'tileJSON',
        url: uri,
        bounds: Array.isArray(json.bounds) ? json.bounds : [-180, -90, 180, 90],
        maxzoom: json.maxzoom ?? 24,
        minzoom: json.minzoom ?? 0,
        identifier: json.id ?? ''
      };
    } else if ('version' in json && 'sources' in json && 'layers' in json) {
      return {
        name: json.name ?? '',
        description: '',
        type: 'mapstyleJSON',
        url: uri
      };
    } else {
      return undefined;
    }
  }
}
