import { create } from 'zustand';
import { v4 as uuidv4 } from 'uuid';
import type { Site, SiteFormData } from '@/types/index.ts';
import { db } from '@/db/schema.ts';

const SITE_COLORS = [
  '#ef4444', '#3b82f6', '#22c55e', '#f59e0b', '#8b5cf6',
  '#ec4899', '#14b8a6', '#f97316', '#6366f1', '#84cc16',
];

interface SitesState {
  sites: Site[];
  selectedSiteId: string | null;
  editingSiteId: string | null;
  isPlacingMode: boolean;
  selectedSiteIds: string[];

  loadSites: () => Promise<void>;
  addSite: (data: SiteFormData) => Promise<Site>;
  updateSite: (id: string, data: Partial<Site>) => Promise<void>;
  deleteSite: (id: string) => Promise<void>;
  selectSite: (id: string | null) => void;
  setEditingSite: (id: string | null) => void;
  togglePlacingMode: () => void;
  setPlacingMode: (val: boolean) => void;

  // Multi-sector
  cloneSiteAsSectors: (siteId: string, sectorCount: 2 | 3) => Promise<void>;
  cloneSector: (siteId: string) => Promise<void>;

  // Import/export
  importSites: (sitesData: SiteFormData[]) => Promise<number>;

  // Batch operations
  toggleSiteSelection: (siteId: string) => void;
  selectAllSites: () => void;
  clearSelection: () => void;
  batchUpdateHeight: (adjustment: number) => Promise<void>;
  batchSetHeight: (height: number) => Promise<void>;
}

export const useSitesStore = create<SitesState>((set, get) => ({
  sites: [],
  selectedSiteId: null,
  editingSiteId: null,
  isPlacingMode: false,
  selectedSiteIds: [],

  loadSites: async () => {
    const dbSites = await db.sites.toArray();
    const sites: Site[] = dbSites.map((s) => ({
      ...JSON.parse(s.data),
      createdAt: new Date(s.createdAt),
      updatedAt: new Date(s.updatedAt),
    }));
    set({ sites });
  },

  addSite: async (data: SiteFormData) => {
    const id = uuidv4();
    const now = new Date();
    const colorIndex = get().sites.length % SITE_COLORS.length;
    const site: Site = {
      ...data,
      id,
      color: data.color || SITE_COLORS[colorIndex],
      visible: true,
      createdAt: now,
      updatedAt: now,
    };
    await db.sites.put({
      id,
      data: JSON.stringify(site),
      createdAt: now.getTime(),
      updatedAt: now.getTime(),
    });
    set((state) => ({ sites: [...state.sites, site] }));
    return site;
  },

  updateSite: async (id: string, data: Partial<Site>) => {
    const sites = get().sites;
    const existing = sites.find((s) => s.id === id);
    if (!existing) return;

    const updated: Site = {
      ...existing,
      ...data,
      updatedAt: new Date(),
    };
    await db.sites.put({
      id,
      data: JSON.stringify(updated),
      createdAt: existing.createdAt.getTime(),
      updatedAt: updated.updatedAt.getTime(),
    });
    set((state) => ({
      sites: state.sites.map((s) => (s.id === id ? updated : s)),
    }));
  },

  deleteSite: async (id: string) => {
    await db.sites.delete(id);
    set((state) => ({
      sites: state.sites.filter((s) => s.id !== id),
      selectedSiteId: state.selectedSiteId === id ? null : state.selectedSiteId,
      editingSiteId: state.editingSiteId === id ? null : state.editingSiteId,
    }));
  },

  selectSite: (id: string | null) => set({ selectedSiteId: id }),
  setEditingSite: (id: string | null) => set({ editingSiteId: id }),
  togglePlacingMode: () => set((s) => ({ isPlacingMode: !s.isPlacingMode })),
  setPlacingMode: (val: boolean) => set({ isPlacingMode: val }),

  // Multi-sector: clone a site into 2 or 3 co-located sector sites
  cloneSiteAsSectors: async (siteId: string, sectorCount: 2 | 3) => {
    const source = get().sites.find((s) => s.id === siteId);
    if (!source) return;

    const spacing = 360 / sectorCount;
    const addSite = get().addSite;

    for (let i = 0; i < sectorCount; i++) {
      const azimuth = Math.round(i * spacing) % 360;
      const label = sectorCount === 2
        ? ['Alpha', 'Beta'][i]
        : ['Alpha', 'Beta', 'Gamma'][i];

      await addSite({
        name: `${source.name}-${label}`,
        lat: source.lat,
        lon: source.lon,
        height: source.height,
        power: source.power,
        gain: source.gain >= 15 ? source.gain : 18, // sector gain default
        frequency: source.frequency,
        antennaType: 'sector',
        azimuth,
        beamwidth: sectorCount === 2 ? 90 : 65,
        color: '',
        visible: true,
        notes: `Sector ${i + 1} (${label}) of ${source.name}`,
      });
    }
  },

  // Clone a single sector: duplicate site with 30° azimuth offset
  cloneSector: async (siteId: string) => {
    const source = get().sites.find((s) => s.id === siteId);
    if (!source) return;

    const addSite = get().addSite;
    const newAzimuth = ((source.azimuth ?? 0) + 30) % 360;

    await addSite({
      name: `${source.name}-clone`,
      lat: source.lat,
      lon: source.lon,
      height: source.height,
      power: source.power,
      gain: source.gain,
      frequency: source.frequency,
      antennaType: source.antennaType,
      azimuth: newAzimuth,
      beamwidth: source.beamwidth,
      color: '',
      visible: true,
      notes: source.notes ? `Clone of: ${source.notes}` : `Clone of ${source.name}`,
    });
  },

  // Import sites from parsed data
  importSites: async (sitesData: SiteFormData[]) => {
    const addSite = get().addSite;
    let count = 0;
    for (const data of sitesData) {
      await addSite(data);
      count++;
    }
    return count;
  },

  // Batch operations
  toggleSiteSelection: (siteId: string) => {
    set((state) => {
      const isSelected = state.selectedSiteIds.includes(siteId);
      return {
        selectedSiteIds: isSelected
          ? state.selectedSiteIds.filter((id) => id !== siteId)
          : [...state.selectedSiteIds, siteId],
      };
    });
  },

  selectAllSites: () => {
    set((state) => ({
      selectedSiteIds: state.sites.map((s) => s.id),
    }));
  },

  clearSelection: () => {
    set({ selectedSiteIds: [] });
  },

  batchUpdateHeight: async (adjustment: number) => {
    const { sites, selectedSiteIds } = get();
    const selectedSet = new Set(selectedSiteIds);
    const now = new Date();

    const updatedSites = sites.map((site) => {
      if (!selectedSet.has(site.id)) return site;
      return {
        ...site,
        height: Math.max(1, Math.min(100, site.height + adjustment)),
        updatedAt: now,
      };
    });

    // Persist to IndexedDB
    const toUpdate = updatedSites.filter((s) => selectedSet.has(s.id));
    for (const site of toUpdate) {
      await db.sites.put({
        id: site.id,
        data: JSON.stringify(site),
        createdAt: site.createdAt.getTime(),
        updatedAt: now.getTime(),
      });
    }

    set({ sites: updatedSites });
  },

  batchSetHeight: async (height: number) => {
    const { sites, selectedSiteIds } = get();
    const selectedSet = new Set(selectedSiteIds);
    const clampedHeight = Math.max(1, Math.min(100, height));
    const now = new Date();

    const updatedSites = sites.map((site) => {
      if (!selectedSet.has(site.id)) return site;
      return {
        ...site,
        height: clampedHeight,
        updatedAt: now,
      };
    });

    // Persist to IndexedDB
    const toUpdate = updatedSites.filter((s) => selectedSet.has(s.id));
    for (const site of toUpdate) {
      await db.sites.put({
        id: site.id,
        data: JSON.stringify(site),
        createdAt: site.createdAt.getTime(),
        updatedAt: now.getTime(),
      });
    }

    set({ sites: updatedSites });
  },
}));
