const path = require('node:path')
const fs = require('node:fs')
const chroma = require('chroma-js')
const PALETTE = require('../dist/colors.meta.json')

const OUTPUT_PATH = path.join(__dirname, '../dist/ios-swift')
const SWIFT_PATH = path.join(OUTPUT_PATH, 'ColorStudioPalette.swift')

function createSwiftRawData(colors) {
  const data = {}
  colors.forEach(colorArray => {
    colorArray.forEach(colorObject => {
      const matches = colorObject.name.replaceAll(/\s+/g, '').match(/^(?<color>\D+)(?<shade>\d*)/)

      if (matches !== null) {
        const color = matches.groups.color
        let shade = String(matches.groups.shade)

        if (shade === '') {
          shade = 'base'
        }

        data[color] ??= {}

        data[color][shade] = chroma(colorObject.value)
      }
    })
  })
  return data
}

function createSwiftCode(data) {
  let output = `// Generated by Color Studio v${PALETTE.version}

import Foundation

#if canImport(UIKit)
import UIKit
#endif

#if canImport(AppKit)
import AppKit
#endif

public enum ColorStudioShade: Int {
    case shade0 = 0
    case shade5
    case shade10
    case shade20
    case shade30
    case shade40
    case shade50
    case shade60
    case shade70
    case shade80
    case shade90
    case shade100
}

#if canImport(UIKit)
public protocol ColorStudioPalette {
    static var colorTable: ColorTable { get }
    static var base: UIColor { get }
}

extension ColorStudioPalette {
    public static func shade(_ shade: ColorStudioShade) -> UIColor {
        colorTable[shade.rawValue]
    }
}

public typealias ColorTable = [UIColor]
#endif

#if canImport(AppKit)
public protocol ColorStudioPalette {
    static var colorTable: ColorTable { get }
    static var base: NSColor { get }
}

extension ColorStudioPalette {
    public static func shade(_ shade: ColorStudioShade) -> NSColor {
        colorTable[shade.rawValue]
    }
}

public typealias ColorTable = [NSColor]
#endif

public struct CSColor {`
  Object.keys(data).forEach(key => {
    const shades = Object.keys(data[key])
    if (shades.length === 1) { // If this is a special color like black or white
      const colorObject = data[key].base
      output += `\n    public struct ${key} {
        /// ${colorObject.hex()} (${colorObject.rgb()})
        public static let base = #colorLiteral(red: ${colorObject.get('rgb.r')}, green: ${colorObject.get('rgb.g')}, blue: ${colorObject.get('rgb.b')}, alpha: ${colorObject.alpha()})
    }\n`
    } else {
      let base = ''
      output += `\n    public struct ${key}: ColorStudioPalette {
        public static let colorTable: ColorTable = [
`
      shades.forEach(shade => {
        const colorObject = data[key][shade]
        if (shade === 'base') {
          base += `        /// ${colorObject.hex()} (${colorObject.rgb()})\n        public static let base = #colorLiteral(red: ${colorObject.get('rgb.r') / 255}, green: ${colorObject.get('rgb.g') / 255}, blue: ${colorObject.get('rgb.b') / 255}, alpha: ${colorObject.alpha()})\n`
        } else {
          output += `            #colorLiteral(red: ${colorObject.get('rgb.r') / 255}, green: ${colorObject.get('rgb.g') / 255}, blue: ${colorObject.get('rgb.b') / 255}, alpha: ${colorObject.alpha()}), // ${shade.padStart(3, ' ')} ${colorObject.hex()} (${colorObject.rgb()})\n`
        }
      })
      output += `        ]\n\n${base}    }\n`
    }
  })
  output += '}\n'
  return output
}

fs.rmSync(OUTPUT_PATH, { recursive: true })
fs.mkdirSync(OUTPUT_PATH)

const swiftData = createSwiftRawData(PALETTE.colors)
const swiftCode = createSwiftCode(swiftData)
fs.writeFileSync(SWIFT_PATH, swiftCode)
