import { isCanvasState, type CanvasState } from "@dada/shared-contracts";

export type BackgroundAdjustments = CanvasState["background"]["adjustments"];

const elementKeys = new Set([
  "colors", "content", "coordinates", "created_at", "dynamic_fields", "element_id", "font_override", "font_size",
  "formatted_value", "opacity", "position", "resource_version", "rotation", "scale", "style_id", "style_parameters",
  "template_or_asset_id", "type", "z_index",
]);

export function defaultBackgroundAdjustments(): BackgroundAdjustments {
  return { brightness: 0, contrast: 0, crop: null, filter: "none", fit: "fill", saturation: 0, sharpness: 0, temperature: 0 };
}

function pixelsForRatio(ratio: CanvasState["ratio"]) {
  return ratio === "3:4" ? { pixelHeight: 1440, pixelWidth: 1080 }
    : ratio === "1:1" ? { pixelHeight: 1080, pixelWidth: 1080 }
      : ratio === "4:3" ? { pixelHeight: 1080, pixelWidth: 1440 }
        : { pixelHeight: 1920, pixelWidth: 1080 };
}

export function createEditorCanvasState(input: { assetId: string | null; ratio: CanvasState["ratio"] }): CanvasState {
  const pixels = pixelsForRatio(input.ratio);
  return {
    background: { adjustments: defaultBackgroundAdjustments(), asset_id: input.assetId },
    elements: [],
    pixel_height: pixels.pixelHeight,
    pixel_width: pixels.pixelWidth,
    ratio: input.ratio,
    schema_version: 1,
  };
}

function checked(state: CanvasState): CanvasState {
  if (!isCanvasState(state)) throw new Error("canvas_state_invalid");
  return structuredClone(state);
}

export function updateBackgroundAdjustments(state: CanvasState, patch: Partial<BackgroundAdjustments>): CanvasState {
  return checked({ ...structuredClone(state), background: { ...state.background, adjustments: { ...state.background.adjustments, ...patch } } });
}

export function resetBackgroundAdjustments(state: CanvasState): CanvasState {
  return checked({ ...structuredClone(state), background: { ...state.background, adjustments: defaultBackgroundAdjustments() } });
}

export function switchBackground(state: CanvasState, assetId: string, palette: readonly string[]): CanvasState {
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(assetId)) throw new Error("canvas_background_asset_invalid");
  if (palette.length !== 5 || palette.some((color) => !/^#[0-9A-Fa-f]{6}$/.test(color))) throw new Error("canvas_palette_invalid");
  const next = structuredClone(state);
  next.background = { asset_id: assetId, adjustments: defaultBackgroundAdjustments() };
  next.elements = next.elements.map((element) => element.type === "color_card" ? { ...element, colors: [...palette] } : element);
  return checked(next);
}

export class CanvasEditHistory {
  private current: CanvasState;
  private readonly past: CanvasState[] = [];
  private readonly future: CanvasState[] = [];

  constructor(initial: CanvasState) { this.current = checked(initial); }
  get value() { return structuredClone(this.current); }
  get canUndo() { return this.past.length > 0; }
  get canRedo() { return this.future.length > 0; }

  commit(next: CanvasState) {
    this.past.push(this.value);
    this.current = checked(next);
    this.future.length = 0;
  }

  undo() {
    const previous = this.past.pop();
    if (!previous) return undefined;
    this.future.push(this.value);
    this.current = previous;
    return this.value;
  }

  redo() {
    const next = this.future.pop();
    if (!next) return undefined;
    this.past.push(this.value);
    this.current = next;
    return this.value;
  }
}

export function deserializeFabricCanvas(input: unknown): CanvasState | undefined {
  if (!input || typeof input !== "object") return undefined;
  const value = input as Record<string, unknown>;
  if (!value.background || typeof value.background !== "object" || !Array.isArray(value.elements)) return undefined;
  const elements = value.elements.map((entry) => {
    if (!entry || typeof entry !== "object" || Object.keys(entry).some((key) => !elementKeys.has(key))) return undefined;
    return structuredClone(entry);
  });
  if (elements.some((entry) => entry === undefined)) return undefined;
  const candidate = {
    background: structuredClone(value.background),
    elements,
    pixel_height: value.pixel_height,
    pixel_width: value.pixel_width,
    ratio: value.ratio,
    schema_version: value.schema_version,
  };
  return isCanvasState(candidate) ? structuredClone(candidate) : undefined;
}

export function cssFilterForBackground(adjustments: BackgroundAdjustments) {
  const filter = adjustments.filter === "grayscale" ? "grayscale(1)" : adjustments.filter === "sepia" ? "sepia(0.75)" : "none";
  return `${filter} brightness(${100 + adjustments.brightness}%) contrast(${100 + adjustments.contrast}%) saturate(${100 + adjustments.saturation}%)`;
}
