-- Migration: 070_locations_module
-- Created: 2026-01-31
-- Version: Location Module v1.0
-- Description: Establishes complete schema for Location (Lokaliteter) Module

-- Table 1: locations_locations
-- Primary use: Store all physical locations (branches, warehouses, service centers, client sites)
-- Soft deletes: true
CREATE TABLE IF NOT EXISTS locations_locations (
  id SERIAL PRIMARY KEY,
  name VARCHAR(255) NOT NULL UNIQUE,
  location_type VARCHAR(50) NOT NULL CHECK(location_type IN ('branch', 'warehouse', 'service_center', 'client_site')),
  address_street VARCHAR(255),
  address_city VARCHAR(100),
  address_postal_code VARCHAR(20),
  address_country VARCHAR(100) NOT NULL DEFAULT 'DK',
  latitude NUMERIC(10, 8),
  longitude NUMERIC(11, 8),
  phone VARCHAR(20),
  email VARCHAR(255),
  notes TEXT,
  is_active BOOLEAN NOT NULL DEFAULT true,
  created_by_user_id INTEGER,
  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
  deleted_at TIMESTAMP
);

CREATE INDEX idx_locations_name ON locations_locations(name);
CREATE INDEX idx_locations_location_type ON locations_locations(location_type);
CREATE INDEX idx_locations_is_active ON locations_locations(is_active);
CREATE INDEX idx_locations_deleted_at ON locations_locations(deleted_at);

-- Table 2: locations_contacts
-- Primary use: Store contact persons associated with each location
-- Soft deletes: true
CREATE TABLE IF NOT EXISTS locations_contacts (
  id SERIAL PRIMARY KEY,
  location_id INTEGER NOT NULL REFERENCES locations_locations(id) ON DELETE CASCADE,
  contact_name VARCHAR(255) NOT NULL,
  contact_email VARCHAR(255),
  contact_phone VARCHAR(20),
  role VARCHAR(100),
  is_primary BOOLEAN NOT NULL DEFAULT false,
  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  deleted_at TIMESTAMP
);

CREATE INDEX idx_locations_contacts_location_id ON locations_contacts(location_id);
CREATE INDEX idx_locations_contacts_is_primary ON locations_contacts(is_primary);
CREATE INDEX idx_locations_contacts_deleted_at ON locations_contacts(deleted_at);

-- Table 3: locations_hours
-- Primary use: Store operating hours for each location (day of week basis)
-- Soft deletes: false
CREATE TABLE IF NOT EXISTS locations_hours (
  id SERIAL PRIMARY KEY,
  location_id INTEGER NOT NULL REFERENCES locations_locations(id) ON DELETE CASCADE,
  day_of_week INTEGER NOT NULL CHECK(day_of_week >= 0 AND day_of_week <= 6),
  open_time TIME,
  close_time TIME,
  is_open BOOLEAN NOT NULL DEFAULT true,
  notes VARCHAR(255)
);

CREATE INDEX idx_locations_hours_location_id ON locations_hours(location_id);
CREATE INDEX idx_locations_hours_day_of_week ON locations_hours(location_id, day_of_week);

-- Table 4: locations_services
-- Primary use: Track services offered at each location
-- Soft deletes: true
CREATE TABLE IF NOT EXISTS locations_services (
  id SERIAL PRIMARY KEY,
  location_id INTEGER NOT NULL REFERENCES locations_locations(id) ON DELETE CASCADE,
  service_name VARCHAR(255) NOT NULL,
  is_available BOOLEAN NOT NULL DEFAULT true,
  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  deleted_at TIMESTAMP
);

CREATE INDEX idx_locations_services_location_id ON locations_services(location_id);
CREATE INDEX idx_locations_services_deleted_at ON locations_services(deleted_at);

-- Table 5: locations_capacity
-- Primary use: Track capacity utilization per location (racks, storage, floor space)
-- Soft deletes: false
CREATE TABLE IF NOT EXISTS locations_capacity (
  id SERIAL PRIMARY KEY,
  location_id INTEGER NOT NULL REFERENCES locations_locations(id) ON DELETE CASCADE,
  capacity_type VARCHAR(100) NOT NULL,
  total_capacity DECIMAL(10, 2) NOT NULL,
  used_capacity DECIMAL(10, 2) NOT NULL DEFAULT 0,
  last_updated TIMESTAMP NOT NULL DEFAULT NOW(),
  CHECK(used_capacity >= 0 AND used_capacity <= total_capacity)
);

CREATE INDEX idx_locations_capacity_location_id ON locations_capacity(location_id);
CREATE INDEX idx_locations_capacity_capacity_type ON locations_capacity(capacity_type);

-- Table 6: locations_audit_log
-- Primary use: Track all changes to locations and related data for compliance and debugging
-- Soft deletes: false
CREATE TABLE IF NOT EXISTS locations_audit_log (
  id SERIAL PRIMARY KEY,
  location_id INTEGER NOT NULL REFERENCES locations_locations(id) ON DELETE CASCADE,
  event_type VARCHAR(50) NOT NULL,
  user_id INTEGER,
  changes JSONB,
  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_locations_audit_log_location_id ON locations_audit_log(location_id);
CREATE INDEX idx_locations_audit_log_event_type ON locations_audit_log(event_type);
CREATE INDEX idx_locations_audit_log_created_at ON locations_audit_log(created_at);

-- Trigger: Update updated_at column on locations_locations
CREATE TRIGGER update_locations_locations_updated_at
BEFORE UPDATE ON locations_locations
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

-- Add comments for documentation
COMMENT ON TABLE locations_locations IS 'Main table storing all physical locations (branches, warehouses, service centers, client sites)';
COMMENT ON TABLE locations_contacts IS 'Contact persons associated with each location (managers, technicians, administrators)';
COMMENT ON TABLE locations_hours IS 'Operating hours for each location by day of week (0=Monday, 6=Sunday)';
COMMENT ON TABLE locations_services IS 'Services offered at each location';
COMMENT ON TABLE locations_capacity IS 'Capacity tracking for locations (rack units, square meters, storage boxes, etc.)';
COMMENT ON TABLE locations_audit_log IS 'Audit trail for all location changes (created, updated, deleted, contact_added, service_added, etc.)';

COMMENT ON COLUMN locations_locations.location_type IS 'Type of location: branch, warehouse, service_center, or client_site';
COMMENT ON COLUMN locations_locations.address_country IS 'Country code, defaults to DK (Denmark)';
COMMENT ON COLUMN locations_locations.latitude IS 'GPS latitude with 8 decimal places precision (approx 1.1mm)';
COMMENT ON COLUMN locations_locations.longitude IS 'GPS longitude with 8 decimal places precision (approx 1.1mm)';
COMMENT ON COLUMN locations_locations.deleted_at IS 'Soft delete timestamp; NULL means active location';

COMMENT ON COLUMN locations_contacts.is_primary IS 'TRUE for primary contact person at location';
COMMENT ON COLUMN locations_contacts.deleted_at IS 'Soft delete timestamp; NULL means active contact';

COMMENT ON COLUMN locations_hours.day_of_week IS '0=Monday, 1=Tuesday, 2=Wednesday, 3=Thursday, 4=Friday, 5=Saturday, 6=Sunday';
COMMENT ON COLUMN locations_hours.is_open IS 'TRUE if location is open on this day; FALSE if closed';

COMMENT ON COLUMN locations_services.is_available IS 'TRUE if service is currently available; FALSE if temporarily unavailable';
COMMENT ON COLUMN locations_services.deleted_at IS 'Soft delete timestamp; NULL means service is active at this location';

COMMENT ON COLUMN locations_capacity.capacity_type IS 'Type of capacity: rack_units, square_meters, storage_boxes, parking_spaces, etc.';
COMMENT ON COLUMN locations_capacity.total_capacity IS 'Total available capacity';
COMMENT ON COLUMN locations_capacity.used_capacity IS 'Currently utilized capacity; must be >= 0 and <= total_capacity';

COMMENT ON COLUMN locations_audit_log.event_type IS 'Type of event: created, updated, deleted, contact_added, contact_removed, service_added, service_removed, hours_updated, capacity_updated, etc.';
COMMENT ON COLUMN locations_audit_log.changes IS 'JSONB object storing before/after values of modified fields';

-- Migration 070_locations_module.sql completed successfully
