/*
 * Copyright (c) 2026 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import cameraDemo from 'libentry.so';

export interface ResolutionSize {
  width: number;
  height: number;
}

export interface SurfaceRectSize {
  surfaceWidth: number;
  surfaceHeight: number;
}

const PREFERRED_LIST: ResolutionSize[] = [
  { width: 2560, height: 1440 }, // 标准5M 16:9
  { width: 2408, height: 1080 },
  { width: 2384, height: 1080 },
  { width: 1920, height: 1440 }, // vision kit 固定分辨率
  { width: 1920, height: 1080 },
  { width: 1440, height: 1080 },
  { width: 1280, height: 720 },
  { width: 1088, height: 1088 },
  { width: 1080, height: 1080 },
  { width: 720, height: 720 },
  { width: 640, height: 480 }, // VGA 4:3
  { width: 480, height: 480 }// 1:1
];

/*********************************************
 * func: 将分辨率转为 123*123 格式
 *********************************************/
function formatLabel(size: ResolutionSize): string {
  return `${size.width}*${size.height}`;
}

/*********************************************
 * func: 分辨率去重
 *********************************************/
function cameraSizeDeduplicate(list: ResolutionSize[]): ResolutionSize[] {
  const seen: Record<string, boolean> = {};
  const out: ResolutionSize[] = [];
  for (const str of list) {
    const key = `${str.width}x${str.height}`;
    if (!seen[key]) {
      seen[key] = true;
      out.push(str);
    }
  }
  return out;
}

/*********************************************
 * func: 将输入转换为标准的CameraSize数组
 *********************************************/
function toCameraSizeArray(anyArr: ResolutionSize[]): ResolutionSize[] {
  const out: ResolutionSize[] = [];
  if (!anyArr || !Array.isArray(anyArr)) {
    return out;
  }
  for (const it of anyArr) {
    const w = Number(it.width);
    const h = Number(it.height);
    if (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {
      out.push({ width: w, height: h });
    }
  }
  return out;
}


/*********************************************
 * func: 将输入转换为标准的CameraSize数组
 *********************************************/
interface SortInterface {
  s: ResolutionSize;
  rank: number;
}



// 获取预置的分辨率并提示哪些分辨率不支持
function sortByPreferred(supported: ResolutionSize[]): ResolutionSize[] {
  const preferredMap = new Map<string, number>();
  PREFERRED_LIST.forEach((p, index) => preferredMap.set(`${p.width}x${p.height}`, index));
  const supportedSet = new Set<string>(supported.map(s => `${s.width}x${s.height}`));

  const filteredPreferred = PREFERRED_LIST.filter(pref => {
    const key = `${pref.width}x${pref.height}`;
    const isSupported = supportedSet.has(key);
    if (!isSupported){
      console.warn(`[Resolution] ${pref.width}x${pref.height} is not supported by the device.`);
    }
    return isSupported;
  });
  return [...PREFERRED_LIST];
}

export class ResolutionService {
  /**
   * 获取并格式化“照片分辨率”。返回字符串数组 ["1920*1080", ...]
   */
  static getPhotoResolutionLabels(): string[] {
    const raw = cameraDemo.getSupportedPhotoResolutions();
    const sizes = sortByPreferred(cameraSizeDeduplicate(toCameraSizeArray(raw)));
    console.info('photoresolutions'+ sizes.map(formatLabel));
    return sizes.map(formatLabel);
  }

  /**
   * 获取并格式化“录像分辨率”。返回字符串数组
   */
  static getVideoResolutionLabels(): string[] {
    const raw = cameraDemo.getSupportedVideoResolutions();
    const sizes = sortByPreferred(cameraSizeDeduplicate(toCameraSizeArray(raw)));
    console.info('videoresolutions'+ sizes.map(formatLabel));
    return sizes.map(formatLabel);
  }

  /**
   * 解析 "W*H" -> {width,height}
   */
  static parseLabel(label: string): ResolutionSize | null {
    if (!label) {
      return null;
    }
    const idx = label.indexOf('*');
    if (idx <= 0) {
      return null;
    }
    const w = Number(label.substring(0, idx));
    const h = Number(label.substring(idx + 1));
    if (!Number.isFinite(w) || !Number.isFinite(h)) {
      return null;
    }
    return { width: w, height: h };
  }

  static applyPhotoResolution(label: string): number {
    const size = ResolutionService.parseLabel(label);
    if (!size) {
      return -1;
    }
    cameraDemo.setPreviewResolution(size.width, size.height);
    return cameraDemo.setPhotoResolution(size.width, size.height);
  }

  static applyVideoResolution(label: string): number {
    const size = ResolutionService.parseLabel(label);
    if (!size) {
      return -1;
    }
    cameraDemo.setPreviewResolution(size.width, size.height);
    return cameraDemo.setVideoResolution(size.width, size.height);
  }

  static detectAspectLabelBySize(photoSize: ResolutionSize): '16:9' | '20:9' | '4:3' | '1:1' | 'other' {
    const photoWidth: number = photoSize.width;
    const photoHeight: number = photoSize.height;
    const aspectRatio: number = photoWidth / photoHeight;
    const isApproximatelyEqual = (value1: number, value2: number, tolerance: number = 0.02): boolean =>
    Math.abs(value1 - value2) <= tolerance;

    if (isApproximatelyEqual(aspectRatio, 16 / 9)) {
      return '16:9';
    }
    if (isApproximatelyEqual(aspectRatio, 20 / 9)) {
      return '20:9';
    }
    if (isApproximatelyEqual(aspectRatio, 4 / 3)) {
      return '4:3';
    }
    if (isApproximatelyEqual(aspectRatio, 1)) {
      return '1:1';
    }
    return 'other';
  }


  static calcSurfaceRectByScreenWidth(photoSize: ResolutionSize, screenWidthInPx: number): SurfaceRectSize {
    const photoWidth = Number(photoSize?.width ?? 0);
    const photoHeight = Number(photoSize?.height ?? 0);
    const screenWidth = Number(screenWidthInPx ?? 0);

    if (!(photoWidth > 0 && photoHeight > 0 && screenWidth > 0)) {
      return { surfaceWidth: 0, surfaceHeight: 0 };
    }

    const aspectLabel = ResolutionService.detectAspectLabelBySize(photoSize);
    const surfaceWidth = Math.round(screenWidth);
    const surfaceHeightFloat = screenWidth * (photoWidth / photoHeight);
    const surfaceHeight = Math.round(surfaceHeightFloat);

    console.info(`[ResolutionService] aspect=${aspectLabel}, W*H=${photoWidth}*${photoHeight}, screenW=${screenWidth}, calcH=${surfaceHeightFloat.toFixed(2)}`);
    return { surfaceWidth, surfaceHeight };
  }
}